hi all, I’m using the FolderItem.Copy to command inside a Thread belonging to a window. In practice, this thread has to copy files in the background. Everything works, but when the file is large, the application freezes anyway and is unlocked when the copy is complete. Being inside a thread I would expect a different behavior.
can anyone explain to me what happens and how to solve it if necessary?
I have already decreased the priority of the thread that copies the files.
I operate on windows 10, xojo 2019 3.1 operating system
I’m speculating that you’re seeing this because threads are cooperative, not preemptive, and that function is blocking.
I should go and review these 2 definitions, I honestly do not remember them at the moment
Solution 1: use an asynchronous Shell to copy the file. It won’t even have to be in a thread.
I had already thought about this solution, but when I finish copying I have to update a record of a database. and in my for the copy of several files is generated. I should therefore N shell as many as there are files. or manage the files one at a time. Other problems arise
Solution 2: write your own copy function that copies the file in chunks in a loop and call that from a thread.
this i don’t know at all how to implement it. Anyway I saw that the problem also exists with different files
Unfortunately, Xojo file IO commands block all threads. I logged case 52196 to add support for non blocking IO.
Solutions…
1.If you have the MBS plugins you could use WindowsFileCopyMBS as that doesn’t block when called within a Xojo thread (NSFileManagerMBS can be used on macOS).
2.Perform the copy via an async shell.
3.Copy the file in blocks.
4.Use a Xojo worker.
It is also worth noting that this is the kind of problem that would be easy to solve if Xojo threads could be pre-emptive rather than cooperative.
1.It will still block when called from the main thread.
2.You need to set the MultiThreaded flag on the class instance.
Here is some rough code i’ve quickly pulled from a project to get you started:
NOTE. pSource & pDestination are both FolderItems.
Const kCOPY_FILE_NO_BUFFERING = &h1000
Dim destFolderItem As FolderItem
Dim copyObj As WindowsFileCopyMBS
Dim copyResult As Boolean
If pDestination.Directory = True Then
destFolderItem = pDestination.Child(pSource.Name)
Else
destFolderItem = pDestination
End If
copyObj = New WindowsFileCopyMBS
copyObj.MultiThreaded = True
'first try with no buffering
copyResult = copyObj.CopyFileEx(pSource, destFolderItem, kCOPY_FILE_NO_BUFFERING)
'if we have an error and it is due to the parameter not being supported on the operating system perform a normal copy
If (copyResult = False) And (copyObj.LastError = 87) Then
copyResult = copyObj.CopyFileEx(pSource, destFolderItem, 0)
End If
Thank you for your suggestion. I’ve used the Shell class before, albeit mostly in synchronous mode. At that point, having several files to delete, I should just create a queue “manager” (a copy might fail, but I would still like to copy all the other files … I should solve with a try / catch inside a for).
Thanks again