Multi-threaded idle handler

I want to create an AppleScript that executes some Finder instructions within an idle handler.

Essentially, I would like to continually poll the list of mounted disks, and when new ones appear, I would like to copy their contents to a server volume.

However, I would like to do this on a machine with more than one CD drive and enable the user perform multiple simultaneous copy operations by inserting more than one disk at a time.

My understanding is that the typical AppleScript idle handler will not work this way. Instead, each (single) Finder copy operation will complete before the code within the idle handler is able to loop again, do a new poll for mounted volumes, and begin a new copy operation.

Am I incorrect on this, or does anyone have ideas on how I might implement this in a way that allows the tasks to run in a parallel, multi-threaded manner?

Cocoa.

Why do you need simultaneous copy operations? You’re mostly limited by disk I/O speed, so you’re not going to gain a ton by moving to multiple threads. Multithreading is a LOT more work than it sounds like. It’s very, very diffcult to get right and not crash or leak all over the place.

It is my understanding that AppleScripts cannot be multithreaded. My approach (fwiw) to your problem would be to write a separate handler for each of the drives because the system will run them simultaneously. On my machine, this identifies a drive:

do shell script "system_profiler | grep -B 4 ATAPI | grep 'Serial Number'"

but you’ll have to fiddle with the first grep to find the second (I only have one).

EDIT: I agree with Mike, however, you won’t gain much by going this way - you are connection-limited, not cpu or hard disk limited. If your problem is that the second CD inserted is not detected while your first is copying, then you’ll have to use this dual approach or set up your script to poll for more periodically.

Mikey-San:

I don’t want simultaneous copy operations from the same disk. I want to copy from multiple disks simultaneously. In the scale at which this must be done (thousands of disks), it will save time, I believe.

Adam:

Thanks for your advice regarding a running script for each device. Can I ask a followup question in terms of syntax? How specifically would you word the Finder scripting to filter for a particular device when polling volumes?

Previously, I was using:

every disk whose ejectable is true

…to poll for every volume.

Whatever you believe, you cannot do this in AppleScript. So the issue is moot.

“If your problem is that the second CD inserted is not detected while your first is copying, then you’ll have to use this dual approach or set up your script to poll for more periodically.”

Let’s toss out the idea of simultaneous copy operations, and assume for the moment that this is my only problem. How could I “set up [my] script to poll for more” while it is still busy copying? It seems I would run into the same no-multi-threading limitation as before.

Are you saying M-S that I can’t run two on idle scripts at the same time? (I do realize that I can’t get the Finder to duplicate two disks at the same time)

That works. It returns an empty list if there are no CD’s inserted and will return 'disk “YourDiskName” ’ if you insert one, but at the end of the day, you’re going to tell the Finder to duplicate the contents somewhere, so once the first copy starts, the Finder won’t start the second. Your ‘on idle’ script would have to continue polling to catch the second. For that to happen, the script doing the copying has to run independently of the ‘on idle’ CD detector, and the CD detector has to note the second disk’s insertion and wait for the first copy to finish before starting the other right away (so you’ll have to test for the ‘copier’ running). You can reassure the user with a dialog. In essence, you’re setting up a queue like a print queue to your ‘dup via the Finder’ engine. I don’t recall how to pass a variable from the ‘detector’ to the ‘copier’ but there is a way.

Not sure any of this is worth it.

[EDIT] Mike can probably think of a way to spawn two shell processes to do it

I said that multithreading in AppleScript was not possible. Notice how he said “will save time, I believe” and then I matched the phrase with “whatever you believe”.

You can run two scripts at once, obviously, but you don’t get run loop or thread control with AppleScript. Even if NSThread somehow works in AppleScript, it shouldn’t be used, because AppleScript doesn’t really provide the correct thread control and memory management system to use it properly.

That implies being able to spawn multiple threads, which AppleScript cannot do. The closest you get is spawning a background process (with the & character command) from a real shell script. You won’t get feedback from those, however, because they’re not “attached”, so to speak, to the AppleScript invocation, and thus don’t return any data to the AppleScript.

If it’s possible to use the & character command in a regular “do shell script” command, you won’t be able to predict when data comes back, so you won’t be able to juggle and check data/variable states sufficiently. (AppleScript can’t use locks and doesn’t have control over what happens in the run loop, so you can’t protect data or manage operations.)

“Mike can probably think of a way to spawn two shell processes to do it”

Now there’s an idea.

What if the volume polling was done by AppleScripting the Finder in an idle handler, and the copy operation(s) were shell processes?

Could I job the copy operation to the shell from AppleScript in a way that AppleScript wouldn’t wait for the operation to complete before moving on with its own life?

I seriously think that this, while academically interesting, isn’t going to get you anywhere but headacheville.

I would just write a shell script or set of them invoked by my AppleScript, and use the most optimization possible. (Copying with ditto instead of the Finder, etc.)

Edit: In fact, if you’re using the shell, you can leave the Finder out of it entirely, most likely, and poll whatever you need to poll with shell commands.

I knew that I couldn’t run two threads, M-S, and I knew that running a shell process wouldn’t let me know what was going on once started. What I had in mind was an ‘on idle’ CD detector that “discovered” each disk insertion and started the shell process to copy it, then followed its progress by monitoring the size of the destination container. When the destination stabilized, the copy is done, and I can inform the user that the disk is copied so another can be loaded. When that disk is ejected, I know it and update my note of it, wait for the next insertion, etc.

Having said all that, as you mentioned originally, unless the sending or receiving machine are extremely busy, the limit on this process is going to be the ‘pipe’, and you aren’t going to stuff any more down it two at a time than one.

I think what rcr is really looking for is not simultaneous transfer as much as a ‘queuer’ like a print queuer so the ‘customer’ will know when the disk is done.

“I seriously think that this, while academically interesting, isn’t going to get you anywhere but headacheville.”

Thank you, Mike. I actually agree with you. This is exactly what I initially told the client that needs this done, but he insisted on being able to process this stuff in parallel. I feel that, with your help, I have done my due diligence here, and will strongly urge him to let me proceed on a single-thread paradigm.

I am glad I asked though. I haven’t hit many situations in the past where I have had to think of scripting in a multi-threaded way, and it is good to wrap my mind around the limitations of AppleScript in this respect.

How does that allow you to handle errors? If something goes wrong, you can’t clean up after or otherwise handle the problem. A lot can go wrong in the shell, so it’s typically good practice to handle it somehow.

If something like this is done, you need to write a full-on shell script, with error handling written into that, and pass it your arguments from AppleScript at invocation. (Even though your AppleScript won’t be able to intercept what’s going on, so you can’t provide any control or feedback for the user or other parts of the script that need to know when something succeeded or failed.) Monitoring a folder via AppleScript won’t do much for you other than act as a rough guess as to what could be going on, maybe, possibly, perhaps.

You’re right about “queueing” here. That’s really what rcr’s client needs: a streamlined queue with good user feedback.

Amen :slight_smile:

Thanks guys.

And you’re both right about the queue. In this case, I think I am just going to push to move ahead as simply as possible (in a single device, non-queued manner), but someday when I have time for my own academic pursuit on this, I want to take a shot at writing a script that does use a queued approach.