Page 1 of 1

Mutex in NXC

Posted: 10 Jan 2011, 01:37
by h-g-t
Been searching the 'net, reading the guides which came with the Bricx Center, etc and I still don't understand mutex.

Does it stop all activity in other tasks while in operation or just prevent the use of any resources used between the two mutex statements?

Advice would be appreciated (preferably in words of half a syllable) or directions to sources of info.

Re: Mutex in NXC

Posted: 10 Jan 2011, 02:51
by mattallen37
Have you heard of the "talking spoon"? It is a general term referring to the method of keeping order (with a spoon), that gets passed around to different individuals. Each person can only talk when they have the spoon. There may be 10 people, but there is only one spoon. In this way, the "talk" will be limited to one person at a time. A mutex was described to me using the same concept. A mutex is a "spoon", and there are (for instance) 10 tasks running. Only the one that "holds" the "spoon" will be able to do anything. To get the "spoon" (mutex), you use the Acquire("mutex"); function ("mutex" is the name of the mutex you want to aquire). To pass the "spoon" to another task, use the Release("mutex"); function.

Re: Mutex in NXC

Posted: 10 Jan 2011, 03:01
by h-g-t
Right, so it stops everything else working - thanks for such a fast response.

Re: Mutex in NXC

Posted: 10 Jan 2011, 03:07
by muntoo
To be exact, it only stops the task when it Acquires for something.

Re: Mutex in NXC

Posted: 10 Jan 2011, 05:30
by m-goldberg
To be a little more exact, when one task acquires a mutex, any other tasks that try to acquire the same mutex are blocked until the first task releases the mutex. At that time, one of the blocked tasks will acquire the mutex and proceed. The other blocked tasks remain blocked.

Re: Mutex in NXC

Posted: 10 Jan 2011, 17:34
by ronmcrae
m-goldberg wrote:To be a little more exact, when one task acquires a mutex, any other tasks that try to acquire the same mutex are blocked until the first task releases the mutex. At that time, one of the blocked tasks will acquire the mutex and proceed. The other blocked tasks remain blocked.
Exactly right. However I wanted to point out that Mutexes are largely used behind-the-scenes by the NXC/NBC compiler so that you program does what you intend it to do when multiple tasks access the same resource. In all the NXC programming I have done I have never had to use a Mutex at the user level. Sure, there are likely legitimate reasons it would be needed, but generally it's not something you need to know about.

Re: Mutex in NXC

Posted: 11 Jan 2011, 02:40
by muntoo
m-goldberg wrote:To be a little more exact...
ronmcrae wrote: Exactly right.
What, level 1.5 exactness not good enough for you? ;)

Basically, this is how mutexes could be implemented (to give the OP a little more understanding):

Code: Select all

#define mutex bool // so mutex is equivalent to saying bool
//typedef bool mutex; // if you're insane, you could also say this instead of the #define


#define FREE 0
#define USED 1


// Not using safecall, because that would imply recursion... I'll leave the geniuses to figure out that cryptic statement
/*safecall*/ inline void Acquire(mutex &var)
{
// Wait till var == FREE
    while(var == USED);
// Claim it for the task that calls this
    var = USED;
}


/*safecall*/ inline void Release(mutex &var)
{
    var = FREE;
}
The above is just an example, of course. Don't actually use this, because it might fail.

Here is how you would use it:

Code: Select all

mutex mMotorA;


task GoForward()
{
    while(1)
    {
        Acquire(mMotorA);
        OnFwd(OUT_A, 100);
        Wait(1000);
        Release(mMotorA);
    }
}

task GoBackward()
{
    while(1)
    {
        Acquire(mMotorA);
        OnRev(OUT_A, 100);
        Wait(1000);
        Release(mMotorA);
    }
}

task main()
{
    // Start tasks
    Precedes(GoForward, GoBackward);
}

Re: Mutex in NXC

Posted: 11 Jan 2011, 03:02
by mattallen37
muntoo wrote:Here is how you would use it:

Code: Select all

mutex mMotorA;


task GoForward()
{
    while(1)
    {
        Acquire(mMotorA);
        OnFwd(OUT_A, 100);
        Release(mMotorA);
    }
}

task GoBackward()
{
    while(1)
    {
        Acquire(mMotorA);
        OnRev(OUT_A, 100);
        Release(mMotorA);
    }
}

task main()
{
    // Start tasks
    Precedes(GoForward, GoBackward);
}
Although, in that example, there aren't any wait functions, so it would change direction way too fast to go much of anywhere.

Re: Mutex in NXC

Posted: 11 Jan 2011, 03:16
by muntoo
mattallen37 wrote:
muntoo wrote:Here is how you would use it:

Code: Select all

mutex mMotorA;


task GoForward()
{
    while(1)
    {
        Acquire(mMotorA);
        OnFwd(OUT_A, 100);
        Release(mMotorA);
    }
}

task GoBackward()
{
    while(1)
    {
        Acquire(mMotorA);
        OnRev(OUT_A, 100);
        Release(mMotorA);
    }
}

task main()
{
    // Start tasks
    Precedes(GoForward, GoBackward);
}
Although, in that example, there aren't any wait functions, so it would change direction way too fast to go much of anywhere.
Did you try running it? ;) Although, I fixed my original code.

Re: Mutex in NXC

Posted: 11 Jan 2011, 04:44
by m-goldberg
ronmcrae wrote:Exactly right. However I wanted to point out that Mutexes are largely used behind-the-scenes by the NXC/NBC compiler so that you program does what you intend it to do when multiple tasks access the same resource. In all the NXC programming I have done I have never had to use a Mutex at the user level. Sure, there are likely legitimate reasons it would be needed, but generally it's not something you need to know about.
What you say here interests me. How would handle this situation?

Suppose you were thinking implementing a program that appeared to require the classic producer/consumer design pattern. That is, where two tasks share a global array as a data buffer which one tasked fills and the other task empties. AFAIK, the NXC will not recognize this situation as requiring a mutex, so the programmer would have to declare one and use Acquire and Release to implement the required critical sections.

Are you saying 1) you can always avoid using this design pattern or 2) you can always eliminate the explicit mutex by implementing the buffer sharing in a shared function protected by safecall?