Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

mutex or semaphores?

5 views
Skip to first unread message

Daniele Cruciani

unread,
Jan 30, 2002, 7:59:54 PM1/30/02
to
Hi,

I've a question that I can't find in FAQ: can I use semaphores
in place of mutex?

I want to warrant mutual exclusion on shared data and thus mutex
should be the right choice, but I can use a semaphore initialized to 1
for that. In what semaphore differ from mutex? (departing from its
need to be released by the same thread which own it)

Also, similar problem:

void fa(){
pthread_mutex_lock(&mymut);
pthread_cond_signal(&mycond);
pthread_mutex_unlock(&mymut);
....;
}

void *sol(void*){
...;
while(1){
pthread_mutex_lock(&mymut);
pthread_cond_wait(&mycond,&mymut);
....;
pthread_mutex_unlock(&mymut);
}
}

or use:
void fa(){
sem_post(cond_sem);
sem_wait(condt_sem);
....;
}

void *sol(void*){
...;
while(1){
sem_wait(cond_sem);
....;
sem_post(condt_sem);
}
}

In my problem there is only one thread that call fa() and sol() is a
thread itself.

All this is in Linux and semaphores is the POSIX one (no shared
between process as far Linux doesn't support it)


thank you in advance,
Daniele.

David Schwartz

unread,
Jan 30, 2002, 8:19:09 PM1/30/02
to
Daniele Cruciani wrote:

> void fa(){
> pthread_mutex_lock(&mymut);
> pthread_cond_signal(&mycond);
> pthread_mutex_unlock(&mymut);
> ....;
> }

What is the purpose of acquiring and releasing the mutex in this code?
What data does the mutex protect?



> void *sol(void*){
> ...;
> while(1){
> pthread_mutex_lock(&mymut);
> pthread_cond_wait(&mycond,&mymut);
> ....;
> pthread_mutex_unlock(&mymut);
> }
> }

Your code calls pthread_cond_wait even if the thing its waiting for has
already happened and fails to call pthread_cond_wait again if the thing
it's waiting for hasn't yet happened. This code should look more like
this:

void *sol(void*){
...;
while(1){
pthread_mutex_lock(&mymut);

while(hasnt_happened_yet())
pthread_cond_wait(&mycond,&mymut);
....;
pthread_mutex_unlock(&mymut);
}
}

This way you don't wait if the thing you're waiting for has already
happened and you wait again in case you wake up and it still hasn't
happened. You don't seem to understand condition variables.

DS

Alexander Terekhov

unread,
Jan 31, 2002, 10:09:05 AM1/31/02
to
Daniele Cruciani <cr...@tiscalinet.it> wrote in message news:<pan.2002.01.31.02...@tiscalinet.it>...

> Hi,
>
> I've a question that I can't find in FAQ: can I use semaphores
> in place of mutex?

If you have a choice, then NEVER use semaphores (IMHO).

> I want to warrant mutual exclusion on shared data and thus mutex
> should be the right choice, but I can use a semaphore initialized to 1
> for that. In what semaphore differ from mutex? (departing from its
> need to be released by the same thread which own it)

Well, since semaphores are actually a mixture of TWO concepts:

a) locking (right choice: mutexes)
b) waiting (right choice: condvars)

they are really BAD:

1) Lock operation is a *cancellation* point!
(and is interruptible by signals: [EINTR])

2) They cannot be used together with condition
variables to build robust synchronization
protocols.

3) They do not support mutex priority protocols;
BEWARE *Priority Inversion*

4) They are slow and error-prone!

Hmmm.. Did I miss something? ;-)

regards,
alexander.

Daniele Cruciani

unread,
Jan 31, 2002, 4:50:37 PM1/31/02
to
On Thu, 31 Jan 2002 16:09:05 +0100, Alexander Terekhov wrote:

> Daniele Cruciani <cr...@tiscalinet.it> wrote in message
> news:<pan.2002.01.31.02...@tiscalinet.it>...
>> Hi,
>>
>> I've a question that I can't find in FAQ: can I use semaphores
>> in place of mutex?
>
> If you have a choice, then NEVER use semaphores (IMHO).
>
>> I want to warrant mutual exclusion on shared data and thus mutex should
>> be the right choice, but I can use a semaphore initialized to 1 for
>> that. In what semaphore differ from mutex? (departing from its need to
>> be released by the same thread which own it)
>
> Well, since semaphores are actually a mixture of TWO concepts:
>
> a) locking (right choice: mutexes)
> b) waiting (right choice: condvars)

conceptually right, but speaking about code, in what they really differ?

>
> they are really BAD:
>
> 1) Lock operation is a *cancellation* point!
> (and is interruptible by signals: [EINTR])

Actually, not a problem: to cancel a thread who have semaphore: wait
for it, cancel it

>
> 2) They cannot be used together with condition
> variables to build robust synchronization protocols.

???

>
> 3) They do not support mutex priority protocols;
> BEWARE *Priority Inversion*

This is really a problem.

>
> 4) They are slow and error-prone!

why slow? why error prone?

>
> Hmmm.. Did I miss something? ;-)

I see, I had a look to the semaphore.h , but still i'm not completely
convinced.
Just to be sure I correctly understand:
For doing this:

void wait(){ /* only a thread execute this */
sem_post(&signal);
sem_wait(&ack);
....;
}

void *do_work(void *arg){
while(1){
sem_wait(&signal);
....;
sem_post(&ack);
....;
}
}

Is better to use:

void wait(){
pthread_mutex_lock(&ack_mutex);
pthread_mutex_lock(&signal_mutex);
pthread_cond_signal(&signal, &signal_mutex);
pthread_mutux_unlock(&signal_mutex);
pthread_cond_wait(&ack);
pthread_mutex_unlock(&ack_mutex);
}

void *do_work(void *arg){
pthread_mutex_lock(&signal_mutex);
while(1){
pthread_cond_wait(&signal,&signal_mutex);
....;
pthread_mutex_lock(&ack_mutex);
pthread_cond_signal(&ack);
pthread_mutex_unlock(&ack_mutex);
....;
}
}

Last one needs 2 mutex and 2 conditions
Linux headers report

in /usr/include/bits/pthreadtypes.h
typedef struct
{
int __m_reserved; /* Reserved for future use */
int __m_count; /* Depth of recursive locking */
_pthread_descr __m_owner; /* Owner thread (if recursive or errcheck) */
int __m_kind; /* Mutex kind: fast, recursive or errcheck */
struct _pthread_fastlock __m_lock; /* Underlying fast lock */
} pthread_mutex_t;

typedef struct
{
struct _pthread_fastlock __c_lock; /* Protect against concurrent access */
_pthread_descr __c_waiting; /* Threads waiting on this
condition */
} pthread_cond_t;

in /usr/include/semaphore.h
typedef struct
{
struct _pthread_fastlock __sem_lock;
int __sem_value;
_pthread_descr __sem_waiting;
} sem_t;

without looking at linux source I suppose _pthread_fastlock is a
kernel managed structure. So

first option:
wait() does
lock s1
test value of s1
raise one from queue of s1
unlock s1
lock s2
test value of s2
insert itself in queue of s2
unlock s2
block
....
done

do_work() does
while(1)
lock s1
test value of s1
insert itself in queue of s1
unlock s1
block
....
lock s2
test value of s2
raise one from queue of s2
unlock s2
....
endw
done

second option:
wait() does
lock m2
lock m1
lock cond1
raise one from queue of cond1
unlock cond1
unlock m1
lock cond2
insert itself in queue of cond2
unlock m2
unlock cond2
block
lock m2
unlock m2
done

do_work() does
lock m1
while(1)
lock cond1
insert itself in queue of cond1
unlock m1
unlock cond1
block
lock m1
....
lock m2
lock cond2
raise one from queue of cond2
unlock cond2
unlock m2
....
endw
done

That come from the fact that pthread_cond_init do not require nothing
about the mutex associated with it. Thus the overhead due to
duplicated system call waste performance in the long run.

IMHO is better to use semaphores here. But I'm new with thread
programming so I'm not so sure.

regard,
Daniele.

David Schwartz

unread,
Jan 31, 2002, 5:41:42 PM1/31/02
to
Daniele Cruciani wrote:

> Is better to use:

Please, read up on condition variables and learn how to use them.

> void wait(){
> pthread_mutex_lock(&ack_mutex);

> pthread_mutex_lock(&signal_mutex);
> pthread_cond_signal(&signal, &signal_mutex);
> pthread_mutux_unlock(&signal_mutex);

What data does the signal_mutex protect? I can't figure out why you're
locking/unlocking a mutex here.

> pthread_cond_wait(&ack);

This function call won't compile.

> pthread_mutex_unlock(&ack_mutex);
> }

Why are you unlocking a mutex? I don't see any shared data that you're
accessing.



> void *do_work(void *arg){
> pthread_mutex_lock(&signal_mutex);
> while(1){
> pthread_cond_wait(&signal,&signal_mutex);
> ....;
> pthread_mutex_lock(&ack_mutex);
> pthread_cond_signal(&ack);
> pthread_mutex_unlock(&ack_mutex);

Again, why are you lock/unlocking the 'ack_mutex'? What shared data is
this mutex supposed to protect?

> ....;
> }
> }

> Last one needs 2 mutex and 2 conditions
> Linux headers report

I can't figure out what either mutex is for. Where's the shared data?
You do understand that mutexes protect shared data, don't you?



> IMHO is better to use semaphores here. But I'm new with thread
> programming so I'm not so sure.

Since you literally have no clue how to use condition variables or
mutexes, I don't think you're in a position to render such a position.

1) Mutexes protect shared data, period.

2) Condition variables must be associated with some sort of condition.

DS

Daniele Cruciani

unread,
Jan 31, 2002, 8:37:31 PM1/31/02
to
On Thu, 31 Jan 2002 23:41:42 +0100, David Schwartz wrote:

> Daniele Cruciani wrote:
>
>> Is better to use:
>
> Please, read up on condition variables and learn how to use them.
>
>> void wait(){
>> pthread_mutex_lock(&ack_mutex);
>
>> pthread_mutex_lock(&signal_mutex);
>> pthread_cond_signal(&signal, &signal_mutex);

neither this compile replace with pthread_cond_signal(&signal);

>> pthread_mutux_unlock(&signal_mutex);
>
> What data does the signal_mutex protect? I can't figure out why you're
> locking/unlocking a mutex here.

Simply I'm assuring that signal won't be lost, period.

>
>> pthread_cond_wait(&ack);
>
> This function call won't compile.

add &ack_mutex

>
>> pthread_mutex_unlock(&ack_mutex);
>> }
>
> Why are you unlocking a mutex? I don't see any shared data that you're
> accessing.

Because in a more realistic scenario there is another thread that can
require this service, here I don't consider it because of space, but this
other thread have exclusive access to this function. Simply here can be a
nosense but there are nothing wrong

>
>> void *do_work(void *arg){
>> pthread_mutex_lock(&signal_mutex);
>> while(1){
>> pthread_cond_wait(&signal,&signal_mutex); ....;
>> pthread_mutex_lock(&ack_mutex);
>> pthread_cond_signal(&ack);
>> pthread_mutex_unlock(&ack_mutex);
>
> Again, why are you lock/unlocking the 'ack_mutex'? What shared data is
> this mutex supposed to protect?

If someone waiting? locking a mutex I'm sure ...

Think about the problem:

T require a service from S, S do it, notify A and does other work.

>
>> ....;
>> }
>> }
>
>> Last one needs 2 mutex and 2 conditions Linux headers report
>
> I can't figure out what either mutex is for. Where's the shared data?
> You do understand that mutexes protect shared data, don't you?
>
>> IMHO is better to use semaphores here. But I'm new with thread
>> programming so I'm not so sure.
>
> Since you literally have no clue how to use condition variables or
> mutexes, I don't think you're in a position to render such a position.

What you had cut in my post is the rationale behind my opinion.
Glibc reference report exactly that you should bind a cond_signal and
cond_wait with lock/unlock if you need to be sure that cond_signal isn't
lost. You can use semaphore in turn, but what really happen in term of
system call? I make an ipotesis, I think it's realistic. and I'm in the
position to say IMHO my ipotesis is realistic.

>
> 1) Mutexes protect shared data, period.

It's a very short answer, what other does? what it means? does the
references on region between lock and unlock are loaded in processor a
time and restored when unlock occur? this is the warrant?

>
> 2) Condition variables must be associated with some sort of condition.

must? why must? I think that in this problem I can use signal, but I find
its unsafe (in linux more than in other system), so I use condition.

Daniele

David Schwartz

unread,
Jan 31, 2002, 9:03:41 PM1/31/02
to

There's a bit of a language barrier, so let me just present some
correct code for using a mutex and a condition variable:

class WakeOne
{
private:
int wakeups;
pthread_mutex_t lock;
pthread_cond_t sig;

public:
WakeOne(void)
{
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&sig, NULL);
wakeups=0;
}
~WakeOne()
{
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&sig);
}
void WaitForever(void)
{
pthread_mutex_lock(&lock);
while(wakeups==0) // loop until a wakeup is sent
pthread_cond_wait(&sig, &lock);
wakeups--;
pthread_mutex_unlock(&lock);
}
void Signal(void)
{
pthread_mutex_lock(&lock);
wakeups++; // make sure a thread will leave its loop
pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond); // wake up a thread
}
}


Note that:

1) The mutexes protect actual shared data (in this case, 'wakeups')

2) The pthread_cond_wait call is called if and so long as there is a
reason to wait and spurious wakeups are correctly handled

These two features are absolutely essential and have been missing from
the code you've posted. You also don't seem to understand how to
properly use pthread_cond_broadcast and pthread_cond_signal as
demonstrated by the fact that you keep wrapping the calls in mutex
lock/unlocks.

DS

David Schwartz

unread,
Jan 31, 2002, 9:07:27 PM1/31/02
to
David Schwartz wrote:

By the way, this code 'saves up' wakeups. If you want 'Signal' to do
nothing if no threads are waiting, you can do this:

class WakeOne
{
private:
int wakeups, waiters;
pthread_mutex_t lock;
pthread_cond_t sig;

public:
WakeOne(void)
{
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&sig, NULL);
wakeups=0;

waiters=0;


}
~WakeOne()
{
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&sig);
}
void WaitForever(void)
{
pthread_mutex_lock(&lock);

waiters++; // there is one more waiter


while(wakeups==0) // loop until a wakeup is sent
pthread_cond_wait(&sig, &lock);

wakeups--; // we consume a wakeup
waiters--; // there is one fewer waiter
pthread_mutex_unlock(&lock);
}
void Signal(void)
{
pthread_mutex_lock(&lock);
if(waiters>0) // send wakeup only if there are waiters


wakeups++; // make sure a thread will leave its loop
pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond); // wake up a thread
}
}

It is a worthwhile exercise to see that, for example, a wakeup can
never be lost and that there is no harm in calling 'pthread_cond_signal'
even if a thread manages to wait after the call to
'pthread_mutex_unlock' on 'Signal'.

DS

Daniele Cruciani

unread,
Jan 31, 2002, 10:58:57 PM1/31/02
to
I see. I was concentrate on implementation and i actually miss the
meaning (and use) of functions.

however there is a reason to use conditions+mutex+shared-data in place
of semaphores?

My use of condition was more like a pthread_kill/sigwait because kill
was my first solution, but I find it's not safe to use signal on a MT
program (in Linux).

(anyway spurious signal was well handled in not cited code)


Daniele

David Schwartz

unread,
Feb 1, 2002, 1:13:15 AM2/1/02
to
Daniele Cruciani wrote:
>
> I see. I was concentrate on implementation and i actually miss the
> meaning (and use) of functions.
>
> however there is a reason to use conditions+mutex+shared-data in place
> of semaphores?

It's faster and more flexible.

DS

Alexander Terekhov

unread,
Feb 1, 2002, 2:41:04 AM2/1/02
to

AFAICT, this will work just fine, except that it could
inject *too many* wakeups. ;-) This race condition is
handled via TWO (sem_waiting and sem_signaled) here:

http://groups.google.com/groups?as_umsgid=3C307EEE.3C49552D%40web.de

regards,
alexander.

Alexander Terekhov

unread,
Feb 1, 2002, 2:42:57 AM2/1/02
to

AFAICT, this will work just fine, except that it could


inject *too many* wakeups. ;-) This race condition is

handled via TWO (sem_waiting and sem_signaled) counters

Alexander Terekhov

unread,
Feb 1, 2002, 2:46:20 AM2/1/02
to
Daniele Cruciani <cr...@tiscalinet.it> wrote in message news:<pan.2002.02.01.02...@tiscalinet.it>...

> On Thu, 31 Jan 2002 23:41:42 +0100, David Schwartz wrote:
>
> > Daniele Cruciani wrote:
> >
> >> Is better to use:
> >
> > Please, read up on condition variables and learn how to use them.
> >
> >> void wait(){
> >> pthread_mutex_lock(&ack_mutex);
>
> >> pthread_mutex_lock(&signal_mutex);
> >> pthread_cond_signal(&signal, &signal_mutex);
>
> neither this compile replace with pthread_cond_signal(&signal);

Sorry, but I must say that you are way too pushy for
a stranger here. May I suggest to you that you should
begin with 1,2,3,4,5 list available here:

http://groups.google.com/groups?as_umsgid=c29b5e33.0201240004.57d109f4%40posting.google.com

<?> ;-)

regards,
alexander.

Daniele Cruciani

unread,
Feb 1, 2002, 10:46:34 AM2/1/02
to
On Fri, 01 Feb 2002 08:46:20 +0100, Alexander Terekhov wrote:

> Daniele Cruciani <cr...@tiscalinet.it> wrote in message
> news:<pan.2002.02.01.02...@tiscalinet.it>...
>> On Thu, 31 Jan 2002 23:41:42 +0100, David Schwartz wrote:
>>
>> > Daniele Cruciani wrote:
>> >
>> >> Is better to use:
>> >
>> > Please, read up on condition variables and learn how to use them.
>> >
>> >> void wait(){
>> >> pthread_mutex_lock(&ack_mutex);
>>
>> >> pthread_mutex_lock(&signal_mutex);
>> >> pthread_cond_signal(&signal, &signal_mutex);
>>
>> neither this compile replace with pthread_cond_signal(&signal);
>
> Sorry, but I must say that you are way too pushy for a stranger here.
> May I suggest to you that you should begin with 1,2,3,4,5 list available
> here:

I care about the problem and I WANT the program behave EXACTLY as it
does with my code. Neither more nor less.

Pretending to say "put something that change shared data in
lock/unlock" without having an idea of what I need is simply stupid.

condition variable are in a single source file, the function wait() is
inside it, no other have access to condition variable, only one can
call wait. These constraint make it useless any shared data. David's
solution (implement a semaphore) don't make my program run faster,
futhermore it make it slower.

this is the prototype:
int pthread_cond_broadcast(pthread_cond_t *COND)
restart all threads that are waiting for condition variable
COND. In my code there is only two thread who know what COND is and
who can reach it.

There are no reason to reimplement semaphores, unless who implement it
is a stupid. (in Linux semaphore is in LinuxThread library)

My question was not "I'm new to thread programming, can you point me
where i can get more info". Simply was "I need to synchronize two
threads in this way (the semaphore example), does is better to use
condition?"

Please, don't damn me with stupid dispute about the use of condition,
I'm interested in BEHAVIOUR of it. I can read hundreds of books, but
when i'm solving a problem i need to know what is better for me, how a
function behave, not the way in which it should be used that is in
mind of who wrote the function initially. (here i'm no stating that i
don't need books)

Maybe I'm stranger here because i think about behaviour. I'd like a
newsgroup in which people can talk about what is better to use saying
because, not simply stating "conceptually ...": I'm not trying to
refuse concept or to elaborate a new teory.

BTW using

lock am
istrue++;
unlock am;
signal a;
lock bm
while(!ack) cond_wait b,bm
ack--
unlock bm

and

lock am;
while(1) {
while(!istrue) cond_wait(b,bm)
istrue--
do something
lock bm;
ack++;
unlock bm;
signal b
other things
}

/* actually I do not need while(!istrue),while(!ack), istrue++, ack++,
ack-- and istue--,but someone pretend to know what I need so I make
him/them happy */

Is the same as using semaphores, thus why does is better to use
conditions HERE? HERE!

Also if you have look at header it seems that it's worst to use
explicit condition and lock in place of semaphores.

No one want to discuss about that. What is better.

>
> http://groups.google.com/groups?as_umsgid=c29b5e33.0201240004.57d109f4%40posting.google.com

Already bookmarked a lot of links and waiting for Butenhof's
book. Thank you, anyway.


Daniele

Alexander Terekhov

unread,
Feb 1, 2002, 2:47:47 PM2/1/02
to
Daniele Cruciani <cr...@tiscalinet.it> wrote in message news:<pan.2002.02.01.16....@tiscalinet.it>...

[...rather emotional/temperamental ;-) stuff (IMHO)...]

> Already bookmarked a lot of links and waiting for Butenhof's
> book.

That's great!

Daniele, please slowdown and read this book first!

Here is the quote from Pg 236/9th Printing:

"If you've got Pthreads, you only _need_ semaphores
to handle this one specialized function--waking a
waiting thread from a signal-catching function."

Well, Butenhof also writes this:

"Just remember that you _can_ use them for other
things when they're convenient and available."

Personally, I tend to avoid semaphores because
of the problems I've outlined earlier in this
thread.

Also, you might want to look at this article:

http://groups.google.com/groups?as_umsgid=slrn9e684t.hp.kaz%40cafe.net

> Thank you, anyway.

You are quite welcome!

regards,
alexander.

0 new messages