Protecting Max/Jitter objects in multi-threaded environment

Apr 30, 2007 at 5:31am

Protecting Max/Jitter objects in multi-threaded environment

I’m in the design phase of a Jitter project that will be using JavaScript. A candidate architecture for the project involves using multiple Max Task objects running asynchronously with respect to each other. In such an environment, with multiple threads running, how does one take care to prevent those threads from modifying objects simultaneously in a way that might leave the object’s state corrupted?

I’ve searched the JavascriptInMax.pdf and the JitterTutorial16.pdf documents, but haven’t found any discussion of the topic. If anyone could direct me to some documentation or examples of how to approach the problem, I’d be grateful.

Thanks in advance,

—Steve

#31665
May 9, 2007 at 10:53am

You would need to start thinking in terms of locks, or other synchronisation systems, for the modifiable objects.
Each process which can modify an object would need to check if the lock’s object is set or clear. If the lock is clear, the process should set it, and start processing, then clear it when its finished. Alternately, if the lock is already set, the process should wait, then retry.

Things can get complicated, but the gist of it can be found here:

http://en.wikipedia.org/wiki/Lock_%28computer_science%29

#103173
May 9, 2007 at 4:51pm

Thanks for the suggestions. I’ll check out the URL you posted. Some kind of locking mechanism is needed for sure, but I’m not sure that JavaScript is up to the task. We may have to rethink our implementation strategy.

Thanks again.

#103174
May 10, 2007 at 10:25am

Its difficult to say without knowing more about the possible implementation, but implementing basic locking in Javascript shouldnt be that hard.
I would be thinking about it in terms of Global objects for the locks, each one corresponding to a buffer or variable you need to protect…
something like this (excuse errors, this may be more like pseudocode than Javascript)

function declare_protected(varname)
{
globalName = “global_” + string(varname);

myglobal = new Global;

eval(“myglobal.globalName = 0″)

}

function set_lock(varname, lock){

globalName = “global_” + string(varname);

myglobal = new Global;

eval(“myglobal.globalName = lock”)
}

function check_lock(varname){

globalName = “global_” + string(varname);

myglobal = new Global;

my lockState = eval(“myglobal.globalName”)
}

function safe_task(){

var locked_var;

if (check_lock(locked_var) == 0)
// lock clear
{
set_lock(locked_var, 1)
do_stuff_to_var(locked_var);
set_lock(locked_var, 1)
}
else{
// lock in use
wait_or_do_nothing()
}
}

#103175
May 16, 2007 at 5:39am

Thank you for your thoughtful response on this topic. The tricky part is implementing the wait_or_do_nothing() method, since JavaScript doesn’t appear to have a sleep() function or a mechanism to wait until a lock is released.

#103176
May 16, 2007 at 9:06pm

Quote: Steve wrote on Wed, 16 May 2007 17:39
—————————————————-
> Thank you for your thoughtful response on this topic. The tricky part is implementing the wait_or_do_nothing() method, since JavaScript doesn’t appear to have a sleep() function or a mechanism to wait until a lock is released.
—————————————————-

Use a callback mechanism, storing a reference to any waiting object(s) in the global, then have the locking object notify the first waiting object when it unlocks.

BTW, eval() is not a good thing to be using if you want best performance.

So, something like this (not tested):

var l = new Global(“locks”);
if(!l.locked) l.locked = new Object;

function doStuff(lockname)
{
if(!l.locked[lockname])
{
l.locked[lockname] = new Object;
l.locked[lockname].locker = this;
l.locked[lockname].waiting = [];
proceed = true;
}
else if(l.locked[lockname].locker == this)
{
proceed = true;
}
else
{
l.locked[lockname].waiting.push(this);
proceed = false;
}
if(proceed)
{
//
// do our stuff here, then
//
if(l.locked[lockname].waiting.length)
{
l.locked[lockname].locker = l.locked[lockname].waiting.shift();
l.locked[lockname].locker.doStuff(lockname) // callback to 1st waiting
}
else
{
delete l.locked[lockname];
}
}
}

#103177
May 17, 2007 at 12:31am

I like this solution. It has support for when the lock is already held by the running process. However, is it possible in a multiple CPU system that 2 or more JavaScript doStuff() functions could be running simultaneously? If so, what happens in the following scenario:

1. Two doStuff() functions are simultaneously running on a 2-CPU system, each function wishing to acquire the same lock, “lockA”.
2. “lockA” does not currently exist.
3. The statement, if(!l.locked[lockname]), at the top of doStuff(), just happens to be executed at the same time (or nearly so) on each CPU and that the statement evaluates to false on both CPUs.

In this situation, won’t both of the doStuff() function instances believe each has exclusive control of “lockA” when only one of them has it? It seems to me that the if-statement and the whole block of code that creates a lock and initializes it needs to be atomic with respect to all other running instances of doStuff()…sort of like a critical section that has the property that once a process starts running the code in the section, no other process in the system can run that code until the first process finishes with the section.

Thanks for the tip on eval(). I’ll use it sparingly.

#103178
May 17, 2007 at 12:48am

Quote: Steve wrote on Thu, 17 May 2007 12:31
—————————————————-
> 3. The statement, if(!l.locked[lockname]), at the top of
> doStuff(), just happens to be executed at the same time (or
> nearly so) on each CPU and that the statement evaluates to
> false on both CPUs.

Hmm. I wonder if that’s even possible.

And I possibly left something important out:

doStuff.immediate = 1;

I think C74 input is needed to answer this…

#103179
May 18, 2007 at 8:35am

Quote: johnpitcairn wrote on Thu, 17 May 2007 02:48
—————————————————-
> Quote: Steve wrote on Thu, 17 May 2007 12:31
> —————————————————-
> > 3. The statement, if(!l.locked[lockname]), at the top of
> > doStuff(), just happens to be executed at the same time (or
> > nearly so) on each CPU and that the statement evaluates to
> > false on both CPUs.
>
> Hmm. I wonder if that’s even possible.

I don’t think so. Currently, that is. Javascript, in fact the whole event mechanism, is executed in one thread (and can only use one processor at a time). This also holds for Task objects, which all run in the same big low-priority thread.

I guess the situation described by Steve is exactly the reason why cycling would have big trouble making the event system work with multiple cores.

Mattijs

>
> And I possibly left something important out:
>
> doStuff.immediate = 1;
>
> I think C74 input is needed to answer this…
>
—————————————————-

#103180

You must be logged in to reply to this topic.