NSAppleScript not in the main thread

  • Hi,

    I just read in the "Multithreading Programing Topics" that
    NSAppleScript should only be used from the main thread.

    My "application" is running as a plug-in in iTunes and I want to
    extend the song information using NSAppleScript.
    As the plug-in is not running in the main thread I could never run my
    AppleScript from the main thread and as NSAppleScript is slow I want
    to create a separate thread for the AppleScript calls.

    What kind of problems can I expect from running AppleScript from
    another thread (and accessing the same application with it)?
    How can I avoid these problems?

    Greeting from Germany
    Christoph Vogelbusch
  • Hi Christoph.

    My program, iTunesSurfer uses NSAppleScript within threads other than
    the main thread. (Amazing what works when you don't know what you
    can't do...) I found, however, that NSApplescript itself is not
    thread safe, so I wrap all uses of it with a BigFatLock(tm).
    Otherwise, I had no problems. Since you are executing within another
    applicaition, there is no guarantee that somebody else won't want to
    use NSApplescript at the same time you do, so you are taking your
    chances there.

    -Kenny

    On May 19, 2006, at 1:47 PM, Christoph Vogelbusch wrote:

    > Hi,
    >
    > I just read in the "Multithreading Programing Topics" that
    > NSAppleScript should only be used from the main thread.
    >
    > My "application" is running as a plug-in in iTunes and I want to
    > extend the song information using NSAppleScript.
    > As the plug-in is not running in the main thread I could never run
    > my AppleScript from the main thread and as NSAppleScript is slow I
    > want to create a separate thread for the AppleScript calls.
    >
    > What kind of problems can I expect from running AppleScript from
    > another thread (and accessing the same application with it)?
    > How can I avoid these problems?
    >
    > Greeting from Germany
    > Christoph Vogelbusch
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/kenny_leung%
    > 40pobox.com
    >
    > This email sent to <kenny_leung...>
    >
  • On May 19, 2006, at 2:47 PM, Christoph Vogelbusch wrote:

    > What kind of problems can I expect from running AppleScript from
    > another thread (and accessing the same application with it)?

    Crashes.

    > How can I avoid these problems?

    You can try playing Russian Roulette with it if you'd like, but the
    documentation change was made after a number of people in this group
    complained that NSAppleScript was crashing while compiling/running
    their script in a thread other than the main thread. For example:
    <http://www.cocoabuilder.com/archive/message/cocoa/2004/8/18/114896>

    The only 100% safe way to run the class is in the main thread.

    Nick Zitzmann
    <http://www.chronosnet.com/>
  • I needed to run an applescript from my application that would send
    events to my application.

    I tried a number of things to make this work with no great success.

    Finally I wrote a little "Script Helper" application.  This faceless
    app can be embedded into my main app's package.  When I need to run a
    script I launch the helper and send it the script.  It can then send
    events back to my main app as needed.    If the helper is idle for
    more than a few minutes it quietly goes away.

    The project is still in development so this has not had a ton of
    testing but, so far it has worked great for me.

    On 19 May 2006, at 4:47 PM, Christoph Vogelbusch wrote:

    > Hi,
    >
    > I just read in the "Multithreading Programing Topics" that
    > NSAppleScript should only be used from the main thread.
    >
    > My "application" is running as a plug-in in iTunes and I want to
    > extend the song information using NSAppleScript.
    > As the plug-in is not running in the main thread I could never run
    > my AppleScript from the main thread and as NSAppleScript is slow I
    > want to create a separate thread for the AppleScript calls.
    >
    > What kind of problems can I expect from running AppleScript from
    > another thread (and accessing the same application with it)?
    > How can I avoid these problems?
    >
    > Greeting from Germany
    > Christoph Vogelbusch
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<craiga...>
    >
    > This email sent to <craiga...>
  • NSAppleScript can only be used in the main thread because it shares a
    AppleScript ComponentInstance, you need to create you own
    ComponentInstance and that can not be done with NSAppleScript, you
    can with my NDAppleScriptObject, which you can get at http://
    homepage.mac.com/nathan_day/

    On 20/05/2006, at 6:47 AM, Christoph Vogelbusch wrote:

    > Hi,
    >
    > I just read in the "Multithreading Programing Topics" that
    > NSAppleScript should only be used from the main thread.
    >
    > My "application" is running as a plug-in in iTunes and I want to
    > extend the song information using NSAppleScript.
    > As the plug-in is not running in the main thread I could never run
    > my AppleScript from the main thread and as NSAppleScript is slow I
    > want to create a separate thread for the AppleScript calls.
    >
    > What kind of problems can I expect from running AppleScript from
    > another thread (and accessing the same application with it)?
    > How can I avoid these problems?
    >
    > Greeting from Germany
    > Christoph Vogelbusch
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<nathan_day...>
    >
    > This email sent to <nathan_day...>

    Nathan Day
    <nathan_day...>
    http://homepage.mac.com/nathan_day/
  • Hi,

    great! Thanks, Nathan. I will try your solution and am very curious
    how you solved that problem.

    Greeting from Germany
    Christoph Vogelbusch

    Am 20.05.2006 um 08:26 schrieb Nathan Day:

    > NSAppleScript can only be used in the main thread because it shares
    > a AppleScript ComponentInstance, you need to create you own
    > ComponentInstance and that can not be done with NSAppleScript, you
    > can with my NDAppleScriptObject, which you can get at http://
    > homepage.mac.com/nathan_day/
    >
    > On 20/05/2006, at 6:47 AM, Christoph Vogelbusch wrote:
    >
    >> Hi,
    >>
    >> I just read in the "Multithreading Programing Topics" that
    >> NSAppleScript should only be used from the main thread.
    >>
    >> My "application" is running as a plug-in in iTunes and I want to
    >> extend the song information using NSAppleScript.
    >> As the plug-in is not running in the main thread I could never run
    >> my AppleScript from the main thread and as NSAppleScript is slow I
    >> want to create a separate thread for the AppleScript calls.
    >>
    >> What kind of problems can I expect from running AppleScript from
    >> another thread (and accessing the same application with it)?
    >> How can I avoid these problems?
    >>
    >> Greeting from Germany
    >> Christoph Vogelbusch
    >> _______________________________________________
    >> Do not post admin requests to the list. They will be ignored.
    >> Cocoa-dev mailing list      (<Cocoa-dev...>)
    >> Help/Unsubscribe/Update your Subscription:
    >> http://lists.apple.com/mailman/options/cocoa-dev/<nathan_day...>
    >>
    >> This email sent to <nathan_day...>
    >
    >
    >
    > Nathan Day
    > <nathan_day...>
    > http://homepage.mac.com/nathan_day/
    >
  • Does that mean I could use NSAppleScript in a secondary thread if
    that is the only thread it will ever be used in?

    Mike.

    On 20 May 2006, at 07:26AM, Nathan Day wrote:

    > NSAppleScript can only be used in the main thread because it shares
    > a AppleScript ComponentInstance, you need to create you own
    > ComponentInstance and that can not be done with NSAppleScript, you
    > can with my NDAppleScriptObject, which you can get at http://
    > homepage.mac.com/nathan_day/
    >
    > On 20/05/2006, at 6:47 AM, Christoph Vogelbusch wrote:
    >
    >> Hi,
    >>
    >> I just read in the "Multithreading Programing Topics" that
    >> NSAppleScript should only be used from the main thread.
    >>
    >> My "application" is running as a plug-in in iTunes and I want to
    >> extend the song information using NSAppleScript.
    >> As the plug-in is not running in the main thread I could never run
    >> my AppleScript from the main thread and as NSAppleScript is slow I
    >> want to create a separate thread for the AppleScript calls.
    >>
    >> What kind of problems can I expect from running AppleScript from
    >> another thread (and accessing the same application with it)?
    >> How can I avoid these problems?
    >>
    >> Greeting from Germany
    >> Christoph Vogelbusch
    >> _______________________________________________
    >> Do not post admin requests to the list. They will be ignored.
    >> Cocoa-dev mailing list      (<Cocoa-dev...>)
    >> Help/Unsubscribe/Update your Subscription:
    >> http://lists.apple.com/mailman/options/cocoa-dev/<nathan_day...>
    >>
    >> This email sent to <nathan_day...>
    >
    >
    >
    > Nathan Day
    > <nathan_day...>
    > http://homepage.mac.com/nathan_day/
    >
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/mike.abdullah%
    > 40gmail.com
    >
    > This email sent to <mike.abdullah...>
  • On 21 maj 2006, at 17.25, Mike Abdullah wrote:

    > Does that mean I could use NSAppleScript in a secondary thread if
    > that is the only thread it will ever be used in?

    I don't know about NSAppleScript in particular (as I've never used
    it), but "main thread" is not equal to "a single, specific, thread".
    If the documented requirement is that you need to use the main
    thread, you can't substitute it for any other thread.

    j o a r
  • All NSAppleScript instance seem to use the same ComponentInstance also the ComponentInstance may also be used by the main thread, to set up the application to be AppleScriptable perhaps. Each thread must have its own AppleScript ComponentInstance, in theory this you could have multiple thread each running there own AppleScript, but I have not been able to get this to work only one AppleScript in a seperate thread to the main thread. NDAppleScriptObject lets you do this, though you are probable better using my replace classes for NDAppleScriptObject, NDScriptData and its descendent class NDScriptHandler and NDScriptContext, I haven't made them available on my web site properly yet as I have not completed the documentation for them I also want to add some more feature and get the multi threading working properly, ie more than one thread running AppleScripts. You can download it here
    <http://homepage.mac.com/nathan_day/.cv/nathan_day/Public/Source%20Code/NDSc
    ript.dmg-binhex.hqx
    >

    On Monday, May 22, 2006, at 01:25AM, Mike Abdullah <mike.abdullah...> wrote:

    >
    > <<Original Attached> >

    Nathan Day
    <nathan_day...>
    http://homepage.mac.com/nathan_day/
  • I'd guess that the main thread could start using AppleScript at any
    time---for example, if another app decided to start sending it
    AppleEvents, or the user opens a document.

    Nathan Day wrote:
    > All NSAppleScript instance seem to use the same ComponentInstance also the ComponentInstance may also be used by the main thread, to set up the application to be AppleScriptable perhaps. Each thread must have its own AppleScript ComponentInstance, in theory this you could have multiple thread each running there own AppleScript, but I have not been able to get this to work only one AppleScript in a seperate thread to the main thread. NDAppleScriptObject lets you do this, though you are probable better using my replace classes for NDAppleScriptObject, NDScriptData and its descendent class NDScriptHandler and NDScriptContext, I haven't made them available on my web site properly yet as I have not completed the documentation for them I also want to add some more feature and get the multi threading working properly, ie more than one thread running AppleScripts. You can download it here
    > <http://homepage.mac.com/nathan_day/.cv/nathan_day/Public/Source%20Code/NDSc
    ript.dmg-binhex.hqx
    >
    >
    > On Monday, May 22, 2006, at 01:25AM, Mike Abdullah <mike.abdullah...> wrote:
    >
    >
    >> <<Original Attached>>
    >>
    >
    >
    > Nathan Day
    > <nathan_day...>
    > http://homepage.mac.com/nathan_day/
    >
    > ------------------------------------------------------------------------
    >
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<jstiles...>
    >
    > This email sent to <jstiles...>
  • Appended is a simplistic-but-effective workaround for the requirement
    that NSAppleScript execute on the main thread.

    The method-of-interest is:

    - (NSAppleEventDescriptor *) executeOnMainThreadReturningError:
    (NSDictionary **) error;

    -- which is modeled on the existing:

    - (NSAppleEventDescriptor *)executeAndReturnError:(NSDictionary **)
    errorInfo;

    -- making this solution an easy drop-in.

    This solution is appropriate when the goal is not expressly to run
    the script in a subthread, but simply to allow a subthread to use the
    script _as_if_ it could run in the subthread. I have found that
    because of the event-synchronized scheduling of events run by
    performSelectorOnMainThread:withObject:waitUntilDone:, the execution
    of reasonably small AppleScripts by this method rarely causes any
    serious disruption in user experience. In some cases even fairly
    large scripts can be broken down into manageable sub-scripts that can
    be executed serially.

    If you are using AppleScript to do something irreducibly time-
    consuming, you probably want to look elsewhere.

    In this solution, the executeOnMainThreadReturningError:  method
    simply executes the script on the main thread using
    performSelectorOnMainThread:withObject:waitUntilDone: and then
    returns the resulting NSAppleEventDescriptor and error dictionary.

    This is not a universal solution -- no support for separately
    compiling the script _from_ the subthread is provided. It is assumed
    that the script has either been precompiled on the main thread, or
    will be compiled at execution.

    It seems to cover the majority of real-world cases, however -- if you
    have a totally "canned" script, it is trivial to precompile it on the
    main thread, and if you don't, you are probably recreating the script
    from scratch with each execution. Compiling from a subthread could
    easily be added, using the current code as a model.

    This could probably be implemented as a category on NSAppleScript by
    using a NSMutableDictionary as the object for
    performSelectorOnMainThread:withObject:waitUntilDone:, but when I
    implemented this I chose the subclass route.

    @interface KKNSAppleScript: NSAppleScript
    {
    NSAppleEventDescriptor * _resultDescriptor;
    NSDictionary * _errorDict;
    }

    - (NSAppleEventDescriptor*)resultDescriptor;
    - (void)setResultDescriptor:(NSAppleEventDescriptor*)inResultDescriptor;

    - (NSDictionary*)errorDict;
    - (void)setErrorDict:(NSDictionary*)inErrorDict;

    - (NSAppleEventDescriptor *) executeOnMainThreadReturningError:
    (NSDictionary **) error;

    @end

    @implementation KKNSAppleScript

    - (NSAppleEventDescriptor*)resultDescriptor
    {
        return _resultDescriptor;
    }

    - (void)setResultDescriptor:(NSAppleEventDescriptor*)inResultDescriptor
    {
        if (_resultDescriptor != inResultDescriptor) {
            [_resultDescriptor release];
            _resultDescriptor = [inResultDescriptor retain];
        }
    }

    - (NSDictionary*)errorDict
    {
        return _errorDict;
    }

    - (void)setErrorDict:(NSDictionary*)inErrorDict
    {
        if (_errorDict != inErrorDict) {
            [_errorDict release];
            _errorDict = [inErrorDict retain];
        }
    }

    - (void) dealloc
    {
    [self setResultDescriptor: nil];
    [self setErrorDict: nil];
    [super dealloc];
    }

    - (void) mainThreadExecute:(id) ignored
    {
    NEWPOOL(pool);
    NSDictionary * error = nil;
    NSAppleEventDescriptor * aed = [self executeAndReturnError: &error];
    [self setErrorDict: error];
    [self setResultDescriptor: aed];
    CLOSEPOOL(pool);
    }

    - (NSAppleEventDescriptor *) executeOnMainThreadReturningError:
    (NSDictionary **) error
    {
    id temp;
    [self performSelectorOnMainThread: @selector(mainThreadExecute:)
    withObject: self waitUntilDone: YES];
    *error = [[[self errorDict] retain] autorelease];
    temp = [[[self resultDescriptor] retain] autorelease];
    [self setResultDescriptor: nil];
    [self setErrorDict: nil];
    return temp;
    }

    @end
  • As I recall, the problem is more extensive than just whether you can
    get AppleScript itself to be thread-safe. Since the user may invoke
    any scripting addition (including standard additions) via their
    script, you have to trust that the scripting additions are themselves
    all thread safe. This problem is similar to the QuickTime vs. QT
    Components issue.  Things are only thread safe if you can limit
    exactly what gets used.

    For instance, I think even the "display dialog" standard addition
    command leads to problems if used on a thread other than the main
    thread.

    As far as I can tell there are two safe approaches to "multitasking
    AppleScript":

    1. Always run scripts on a separate process.
    2. Mess around with AppleScript/AppleEvents callbacks that give you
    time to continue running the event loop while a script is running.

    In my experience #2 does not give an ideal user experience, while #1
    does not give ideal performance.

    Daniel

    On May 22, 2006, at 2:02 AM, Nathan Day wrote:

    > All NSAppleScript instance seem to use the same ComponentInstance
    > also the ComponentInstance may also be used by the main thread, to
    > set up the application to be AppleScriptable perhaps. Each thread
    > must have its own AppleScript ComponentInstance, in theory this you
    > could have multiple thread each running there own AppleScript, but
    > I have not been able to get this to work only one AppleScript in a
    > seperate thread to the main thread. NDAppleScriptObject lets you do
    > this, though you are probable better using my replace classes for
    > NDAppleScriptObject, NDScriptData and its descendent class
    > NDScriptHandler and NDScriptContext, I haven't made them available
    > on my web site properly yet as I have not completed the
    > documentation for them I also want to add some more feature and get
    > the multi threading working properly, ie more than one thread
    > running AppleScripts. You can download it here
    > <http://homepage.mac.com/nathan_day/.cv/nathan_day/Public/Source%
    > 20Code/NDScript.dmg-binhex.hqx>
    >
    > On Monday, May 22, 2006, at 01:25AM, Mike Abdullah
    > <mike.abdullah...> wrote:
    >
    >>
    >> <<Original Attached>>
    >
    >
    > Nathan Day
    > <nathan_day...>
    > http://homepage.mac.com/nathan_day/
    > _______________________________________________
    > Do not post admin requests to the list. They will be ignored.
    > Cocoa-dev mailing list      (<Cocoa-dev...>)
    > Help/Unsubscribe/Update your Subscription:
    > http://lists.apple.com/mailman/options/cocoa-dev/<jalkut...>-
    > sweater.com
    >
    > This email sent to <jalkut...>
  • My ComponentInstance class than comes with NDAppleScriptObject allows
    you to catch every NSAppleEvent that the AppleScript attempts to
    send, you can then resend it yourself in the main thread.

    On 30/05/2006, at 3:24 AM, Daniel Jalkut wrote:

    > As I recall, the problem is more extensive than just whether you
    > can get AppleScript itself to be thread-safe. Since the user may
    > invoke any scripting addition (including standard additions) via
    > their script, you have to trust that the scripting additions are
    > themselves all thread safe. This problem is similar to the
    > QuickTime vs. QT Components issue.  Things are only thread safe if
    > you can limit exactly what gets used.
    >
    > For instance, I think even the "display dialog" standard addition
    > command leads to problems if used on a thread other than the main
    > thread.
    >
    > As far as I can tell there are two safe approaches to "multitasking
    > AppleScript":
    >
    > 1. Always run scripts on a separate process.
    > 2. Mess around with AppleScript/AppleEvents callbacks that give you
    > time to continue running the event loop while a script is running.
    >
    > In my experience #2 does not give an ideal user experience, while
    > #1 does not give ideal performance.
    >
    > Daniel
    >
    > On May 22, 2006, at 2:02 AM, Nathan Day wrote:
    >
    >> All NSAppleScript instance seem to use the same ComponentInstance
    >> also the ComponentInstance may also be used by the main thread, to
    >> set up the application to be AppleScriptable perhaps. Each thread
    >> must have its own AppleScript ComponentInstance, in theory this
    >> you could have multiple thread each running there own AppleScript,
    >> but I have not been able to get this to work only one AppleScript
    >> in a seperate thread to the main thread. NDAppleScriptObject lets
    >> you do this, though you are probable better using my replace
    >> classes for NDAppleScriptObject, NDScriptData and its descendent
    >> class NDScriptHandler and NDScriptContext, I haven't made them
    >> available on my web site properly yet as I have not completed the
    >> documentation for them I also want to add some more feature and
    >> get the multi threading working properly, ie more than one thread
    >> running AppleScripts. You can download it here
    >> <http://homepage.mac.com/nathan_day/.cv/nathan_day/Public/Source%
    >> 20Code/NDScript.dmg-binhex.hqx>
    >>
    >> On Monday, May 22, 2006, at 01:25AM, Mike Abdullah
    >> <mike.abdullah...> wrote:
    >>
    >>>
    >>> <<Original Attached>>
    >>
    >>
    >> Nathan Day
    >> <nathan_day...>
    >> http://homepage.mac.com/nathan_day/
    >> _______________________________________________
    >> Do not post admin requests to the list. They will be ignored.
    >> Cocoa-dev mailing list      (<Cocoa-dev...>)
    >> Help/Unsubscribe/Update your Subscription:
    >> http://lists.apple.com/mailman/options/cocoa-dev/<jalkut...>-
    >> sweater.com
    >>
    >> This email sent to <jalkut...>
    >

    Nathan Day
    <nathan_day...>
    http://homepage.mac.com/nathan_day/
  • That's interesting - but doesn't that present the undesirable
    behavior of an AppleScript blocking on the main thread (while waiting
    for an AppleEvent reply). Isn't that one motivation for moving it to
    a separate thread in the first place?

    Daniel

    On May 30, 2006, at 10:18 AM, Nathan Day wrote:

    > My ComponentInstance class than comes with NDAppleScriptObject
    > allows you to catch every NSAppleEvent that the AppleScript
    > attempts to send, you can then resend it yourself in the main thread.
  • Yes, but in practice it doesn't matter, you can filter all the
    AppeEvent directed to your own application and only send them in the
    main thread, and when your main thread handles an AppleEvent it
    either only block very briefly so the user does not notice it or its
    for something like display dialog, in which case you are wanting for
    the user to supply input.

    The point is it does not block for the entire duration of your script.

    On 31/05/2006, at 12:42 AM, Daniel Jalkut wrote:

    > That's interesting - but doesn't that present the undesirable
    > behavior of an AppleScript blocking on the main thread (while
    > waiting for an AppleEvent reply). Isn't that one motivation for
    > moving it to a separate thread in the first place?
    >
    > Daniel
    >
    > On May 30, 2006, at 10:18 AM, Nathan Day wrote:
    >
    >> My ComponentInstance class than comes with NDAppleScriptObject
    >> allows you to catch every NSAppleEvent that the AppleScript
    >> attempts to send, you can then resend it yourself in the main thread.
    >

    Nathan Day
    <nathan_day...>
    http://homepage.mac.com/nathan_day/
previous month may 2006 next month
MTWTFSS
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
Go to today