problem with backgroundworker

Apr 4, 2014 at 12:03 AM
I am using the Microsoft.ClearScript.Windows.VBScriptEngine object.

I have it inside a large class. Everything runs just great until I call one of the class's functions with a backgroundworker.

In that scenario when I try to ExecuteCommand I get this error


"The calling thread cannot access this object because a different thread owns it."

I saw where I can call the CheckAccess() function to keep it from the error but I really really need this to work same as if it was all on a single thread.

this is how I am initiating the vb object
  WorkflowVBS = new Microsoft.ClearScript.Windows.VBScriptEngine("ALICE");
added these lines but they don't seem to help at all.
  WorkflowVBS.VerifyAccess();
  WorkflowVBS.AllowReflection = true;
There has to be a way out of this pickle. just has to be.
Apr 4, 2014 at 1:31 AM
Had an aha moment and thought declaring WofkflowVBS static would save the day. No joy.
Coordinator
Apr 4, 2014 at 3:01 PM
Hello notahack,

Windows script engines (JScript/VBScript) have thread affinity; that is, each instance can only be accessed on the thread that created it.

ClearScript supports this requirement by associating each WindowsScriptEngine instance with a Dispatcher that you can use to invoke operations on the appropriate thread.

Depending on your application's architecture, such invocations may or may not have to be asynchronous. Here's an example of a synchronous one:
engine.Dispatcher.Invoke(new Action(() => engine.Execute(scriptCode)));
Good luck!
Apr 4, 2014 at 11:39 PM
that worked but not for all situations.

When I am running with in the ide or a compiled program with a visual interface that worked. Take the same code and put it into a windows application that I am running on the command line and it bombs, even with error trapping.

public bool WF_Script_Run(int Index)
        {

            bool retval = true;
            string errmsg = "";

            WF.SO.cancel = false;

            if (WF.OK && WF.SCEvent[Index])
            {
                try
                {
                    if ((int)WF.RunVersion < -10)
                    {
                        WorkflowJS.ExecuteCommand(WF.SCEvent_Names[Index]);
                    }
                    else
                    {
                        if (WorkflowVBS.CheckAccess())
                        {
                            WorkflowVBS.ExecuteCommand(WF.SCEvent_Names[Index]);
                        }
                        else
                        {
                            WorkflowVBS.Dispatcher.Invoke(new Action(() => WorkflowVBS.ExecuteCommand(WF.SCEvent_Names[Index])));
                        }
                    }
                }
                catch (Microsoft.ClearScript.ScriptEngineException EX)
                {
                    errmsg = EX.Message;
                }
                catch (Exception EX)
                {
                    errmsg = EX.Message;    

                }



            }

            return retval;
        }
Coordinator
Apr 5, 2014 at 11:59 AM
Edited Apr 5, 2014 at 12:10 PM
Hi again,

Can you elaborate on "it bombs"? If the target thread is waiting for keyboard input via System.Console.ReadLine() or something like that, then invoking through the dispatcher should block. If you're seeing an exception, what is it?

In general, if the target thread isn't a message-pumping thread (e.g., a GUI thread), then invoking through the dispatcher isn't likely to work, and you'll have to come up with your own way to ensure that the script engine is accessed only on that thread.

Cheers!
Apr 5, 2014 at 9:10 PM
On second thought maybe it didn't "bomb", i.e. generate a run time error, since my error trapping didn't trap anything. Instead I think it ran the line

WorkflowVBS.Dispatcher.Invoke(new Action(() => WorkflowVBS.ExecuteCommand(WF.SCEvent_Names[Index])));

and just hanged. Is that possible?

On the calling thread I used System.Threading.AutoResetEvent. WaitOne and Set to block until the background worker thread completed. Any other suggestion?

I got past it by rewriting the windows program as a single thread since it runs from a command line. 90% of the time code calling scripting will be single thread and if not it will be called in a separate thread to keep the GUI alive. I will be using a lot of command line and service programs so I am very concerned that the scripting code will not run in those environments if I use multi threads.

I will admit I am a noob to multithreading in C# or any other language. Your statement "you'll have to come up with your own way to ensure that the script engine is accessed only on that thread." may as well be in pig latin to my understanding. To my knowledge there are only 2 threads, the calling and the backgroundworker.

I assume this scenario also applies to the microsoft javascript. Does it apply to the V8 engine also?

Give me a clue and a homework assignment kind sir. I am appreciative of your assistance.
Coordinator
Apr 6, 2014 at 6:20 PM
Hi notahack,

and just hanged. Is that possible?

Yes, absolutely. For synchronous invocation, the calling thread must wait until the target thread is done executing the call. In your case, the target thread is waiting for an event signal, so it is unavailable to execute the call, and you get deadlock.

We can't help much without knowing your application's architecture. APIs provide various tools for achieving correctness and robustness in multithreaded programs; the dispatcher is just one such tool. The key to using it is that the target thread (the one that owns the dispatcher) must be coded a certain way; specifically, it must process the dispatch queue. Windows GUI threads typically do this, but custom threads can use methods such as Dispatcher.PushFrame().

Check out the MSDN documentation in this area, but remember that the dispatcher is just one tool. The engine's only requirement is that you always access it on the thread that created it, and there are many ways to accomplish that.

I assume this scenario also applies to the microsoft javascript. Does it apply to the V8 engine also?

V8ScriptEngine instances don't have thread affinity, but they don't support concurrent access either. Each instance is protected by a lock, but there are still plenty of ways to get into trouble :)

Good luck!