Program freezes 30 sec while accessing a disconnected drive
I have this piece of code that drives me mad.
FUNCTION DiskInDrive(CONST DriveNumber: Byte): BOOLEAN;
VAR ErrorMode : Word;
BEGIN
RESULT:= FALSE;
ErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
TRY
if DiskSize(DriveNumber) <> -1 { %%%% THIS IS VERY SLOW IF THE DISK IS NOT IN DRIVE !!!!!! }
THEN RESULT:= TRUE;
FINALLY
SetErrorMode(ErrorMode);
END;
END;
It checks if a disk is ready to be used (and also if the provided drive letter corresponds to a valid disk). The problem is that when I try to access a disconnected network drive (network folder mapped as drive), it freezes开发者_Python百科 for about 10-30 seconds.
The code is in the constructor of a component I made.
How can I check a drive without waiting that long?
First, you have to realize that you have to wait. Accessing removable media which hasn't been cached is an expensive operation that depends on many different things (drivers, manufacturer, quality of the media, operating system version, service packs, antivirus installed, etc.)
Once you have come up to terms with this, you don't have to get your application to actually freeze. I don't have Delphi here, but what I would do is
- Create a new
TThreadedObject
and put theDiskInDrive
logic in its Execute method - Use a variable to set / get this result
- Enable / disable the appropriate visual controls.
This way you still have to wait, but your application won't become unresponsive. You can even add the option of cancelling the operation (in case the operation takes too long to complete.)
As far as I know, it's simply unavoidable that doing something with a network drive may lock up the calling thread while Windows tries to access the network drive. It's one of those leaky abstractions that Joel Spolsky talks about.
Your best bet is to do your drive checking from a separate thread so that it doesn't lock up the UI. (Delphi 2009's generics or Jon Schemitz' MsgWaits library can simplify the necessary multithreading code.)
Create a component in delphi with a worker thread, and replace your call to this function with a call to a routine that creates or picks up a worker thread from a pool, and starts this work. then if the code times out, return FALSE. So disk is not in drive if it's timing out.
The code will complete in its time, and return the thread to the pool.
精彩评论