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

Do I ever need to do a sched_yield() for pthread_cond_signal(..) to work?

210 views
Skip to first unread message

Nelson Castillo

unread,
Feb 18, 2008, 2:43:35 PM2/18/08
to
Hi.

I have this source code that prints 1000 in a few desktop machines
(Linux NTPL, Linux 2.6.24).

http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test.c

* Does it also print 1000 for you?
* Following the POSIX standard, should it always print 1000?

I am working with Linux + Realtime patches, and it prints 1 or 0,
unless I do a call to sched_yield() after releasing the mutex
associated with the condition. And I'd like to know If I have made
a wrong assumption.

void
dosignal (void)
{
pthread_mutex_lock (&cond_mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock (&cond_mutex);
/* sched_yield(); without this I get 0! with Linux and RT patches
*/
}

Is it guaranteed (by the standard) that after:

pthread_cond_signal(&cond);
pthread_mutex_unlock (&cond_mutex);

a thread waiting for the condition must wake up?

Regards,
Nelson.-

--
http://arhuaco.org

Szabolcs Ferenczi

unread,
Feb 18, 2008, 4:34:39 PM2/18/08
to
On Feb 18, 8:43 pm, Nelson Castillo <nelson...@gmail.com> wrote:

> Is it guaranteed (by the standard) that after:
>
>   pthread_cond_signal(&cond);
>   pthread_mutex_unlock (&cond_mutex);
>
> a thread waiting for the condition must wake up?

No. By the signal you express that the signaled thread _may_ continue.
By the unlock you express that you leave the critical region and other
threads _may_ enter it.

That is all.

I would say, in a well designed system you do not have to use yield at
all.

Best Regards,
Szabolcs

Nelson Castillo

unread,
Feb 18, 2008, 4:40:00 PM2/18/08
to
On Feb 18, 4:34 pm, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:

> On Feb 18, 8:43 pm, Nelson Castillo <nelson...@gmail.com> wrote:
>
> > Is it guaranteed (by the standard) that after:
>
> >   pthread_cond_signal(&cond);
> >   pthread_mutex_unlock (&cond_mutex);
>
> > a thread waiting for the condition must wake up?
>
> No. By the signal you express that the signaled thread _may_ continue.
> By the unlock you express that you leave the critical region and other
> threads _may_ enter it.

Ah, Ok. Thanks.

> I would say, in a well designed system you do not have to use yield at
> all.

Sure :) Thanks for the reply.

Regards,
Nelson.-

Szabolcs Ferenczi

unread,
Feb 18, 2008, 4:46:40 PM2/18/08
to
On Feb 18, 8:43 pm, Nelson Castillo <nelson...@gmail.com> wrote:
> Hi.
>
> I have this source code that prints 1000 in a few desktop machines
> (Linux NTPL, Linux 2.6.24).
>
> http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test.c
>
> *  Does it also print 1000 for you?

Sometimes. Sometimes not. It can print anything.

$ g++ -o cond-signal-test cond-signal-test.c -lpthread
$ ./cond-signal-test.o
997
$ ./cond-signal-test.o
967
$ ./cond-signal-test.o
1000
$ ./cond-signal-test.o
974
$ ./cond-signal-test.o
958
$ ./cond-signal-test.o
624
$ uname -a
Linux smaug 2.4.21-40.ELsmp #1 SMP Thu Feb 2 22:22:39 EST 2006 i686
i686 i386 GNU/Linux

Best Regards,
Szabolcs

Szabolcs Ferenczi

unread,
Feb 18, 2008, 4:54:26 PM2/18/08
to
On Feb 18, 8:43 pm, Nelson Castillo <nelson...@gmail.com> wrote:

> I have this source code that prints 1000 in a few desktop machines
> (Linux NTPL, Linux 2.6.24).
>
> http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test.c

What would you like to achieve with this program? Let us see what we
can change on it to get a correct concurrent program. I am trying to
help, if you like.

Best Regards,
Szabolcs

Nelson Castillo

unread,
Feb 18, 2008, 6:23:59 PM2/18/08
to
On Feb 18, 4:54 pm, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:

Thanks all for your tests and help. This is the original code, where I
have the problem:

http://svn.arhuaco.org/svn/src/junk/trunk/threads/test_timer.c


This is a timer that can be scheduled, cancelled, and then scheduled
again.
It is not working. After "no function call should be made " nothing
else should be printed.

There is what it prints when it doesn't work:

no function call should be made ... waiting for task:3
waiting for task:2
waiting for task:1
waiting for task:0
not waiting for tasks!
- test_f (id:3) called after 3501 ms
- test_f (id:2) called after 3501 ms
- test_f (id:1) called after 3501 ms
- test_f (id:0) called after 3501 ms
OK?
sleeping forever

The problem is that the following function is sending a signal, and
the signal is
associated to 2 parameters. However, I'm not waiting for the action to
be completed.
I guess I need to use another condition.

timer_cancel (int job)
{
pthread_mutex_lock (&timer_mutex);

stack_action_arg = job;
stack_action = REMOVE_TIMER;
pthread_cond_signal(&timer_cond);

pthread_mutex_unlock (&timer_mutex);
/* sched_yield(); // bad design, fix the problem */

return 0;
}

This is what the thread that receives the signal looks like:

static void *
timer_exec(void *arg)
{
pthread_mutex_lock (&timer_mutex); /* unlocked when waiting for
condition */

timer_exec_next:

switch (stack_action) /* here is the action to be done when a signal
is received */
{
case REMOVE_TIMER: unlink_task_node(tasks[stack_action_arg]);
break; /* what I care about */
default: break;
}

stack_action = ACTION_NONE;

if (<<nothing to do>>)
pthread_cond_wait (&timer_cond, &timer_mutex);
else
{
<<we need to wait here for a Timeout or a signal >>
pthread_cond_timedwait(&timer_cond, &timer_mutex, ...);
..
}

goto timer_exec_next;
}


I guess I need to use another signal to tell timer_cancel(...) that
the work has been
done. Right? What is the best way to do it?

Regards,
Nelson.-

Nelson Castillo

unread,
Feb 18, 2008, 6:49:49 PM2/18/08
to
> I guess I need to use another signal to tell timer_cancel(...) that
> the work has been
> done. Right? What is the best way to do it?

I think this example will help me. I think I can try to solve this
with the producer-consumer
pattern.

http://www.cs.nmsu.edu/~jcook/Tools/pthreads/pc.c

It compiles after 10 years :) (changing #ifdef 0 => #if 0).

Is it OK to signal a condition after releasing the mutex?

pthread_mutex_unlock (fifo->mut);
pthread_cond_signal (fifo->notFull);

I think the man page of pthread_cond_signal(3) confused me.

The pthread_cond_broadcast() or pthread_cond_signal() functions may
be called by a thread
whether or not it currently owns the mutex that threads calling
pthread_cond_wait() or
pthread_cond_timedwait() have associated with the condition
variable during their waits;
however, if predictable scheduling behavior is required, then that
mutex shall be locked
by the thread calling pthread_cond_broadcast() or
pthread_cond_signal().

What does "predictable scheduling" mean in this context?

Regards,
Nelson.-

David Schwartz

unread,
Feb 18, 2008, 7:53:58 PM2/18/08
to
On Feb 18, 3:23 pm, Nelson Castillo <nelson...@gmail.com> wrote:

> The problem is that the following function is sending a signal, and
> the signal is
> associated to 2 parameters. However, I'm not waiting for the action to
> be completed.
> I guess I need to use another condition.

Your timer function should:

1) Get the timer information.
2) Set the timer's state to "firing".
3) Release the mutex.
4) Run the timer function.
5) Acquire the mutex.
6) Set the timer's state to "fired".
7) Release the mutex.

This way, a thread that cancels the timer can tell, for sure, whether
the timer has already fired. Otherwise, if you find the timer pulled,
you don't know if the function has run yet or is yet to be run.

DS

Nelson Castillo

unread,
Feb 18, 2008, 9:10:24 PM2/18/08
to
On Feb 18, 7:53 pm, David Schwartz <dav...@webmaster.com> wrote:
> On Feb 18, 3:23 pm, Nelson Castillo <nelson...@gmail.com> wrote:
>
> > The problem is that the following function is sending a signal, and
> > the signal is
> > associated to 2 parameters. However, I'm not waiting for the action to
> > be completed.
> > I guess I need to use another condition.

Thanks a lot for your feedback (to all who replied). I think I will
not
have problems with the implementation from now on. For the record, I
fixed
the example and I think it's OK (at least much better) now.

http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test-ok.c

Definitely, sched_yield and (almost)busy waiting with usleeps are bad
design.

> Your timer function should:
>
> 1) Get the timer information.
> 2) Set the timer's state to "firing".
> 3) Release the mutex.
> 4) Run the timer function.
> 5) Acquire the mutex.
> 6) Set the timer's state to "fired".
> 7) Release the mutex.
>
> This way, a thread that cancels the timer can tell, for sure, whether
> the timer has already fired. Otherwise, if you find the timer pulled,
> you don't know if the function has run yet or is yet to be run.

Sure :) Thanks a lot. Actually, there will be more than one timer.
The
event "cancel" tries to remove an element from a list of pending
timers.
I got confused because I needed something similar to producer-consumer
(but without a queue) and I hadn't used more than one condition
associated
to a mutex before (or perhaps I did MANY years ago).

Regards,
Nelson.-

Markus Elfring

unread,
Feb 19, 2008, 2:59:43 PM2/19/08
to
> Thanks all for your tests and help. This is the original code, where I
> have the problem:
> http://svn.arhuaco.org/svn/src/junk/trunk/threads/test_timer.c

I suggest to add checks for return values to all relevant function calls.
Would you like to detect every error situation as early as possible?

Regards,
Markus

Markus Elfring

unread,
Feb 19, 2008, 3:27:35 PM2/19/08
to
> Is it OK to signal a condition after releasing the mutex?

Yes. - Would you like to look at previous discussions?
Example: "A word of caution when juggling pthread_cond_signal/pthread_mutex_unlock"
http://groups.google.de/group/comp.programming.threads/msg/7e5fcdf360543375


> What does "predictable scheduling" mean in this context?

Can any answers from the discussion "pthread_cond_* implementation questions"
help in better understanding of the involved dependencies?
http://groups.google.de/group/comp.programming.threads/msg/0a3cb5018bf5c6c5

Regards,
Markus

Nelson Castillo

unread,
Feb 20, 2008, 8:06:09 AM2/20/08
to
On Feb 19, 3:27 pm, Markus Elfring <Markus.Elfr...@web.de> wrote:
> > Is it OK to signal a condition after releasing the mutex?
>
> Yes. - Would you like to look at previous discussions?
> Example: "A word of caution when juggling pthread_cond_signal/pthread_mutex_unlock"http://groups.google.de/group/comp.programming.threads/msg/7e5fcdf360...

It says:

the worker_destroy() method might actually acquire
the worker's mutex immediately after it is released but
before the condition variable is signalled, right in the gap
between the unlock and the signal.

> > What does "predictable scheduling" mean in this context?
>
> Can any answers from the discussion "pthread_cond_* implementation questions"

> help in better understanding of the involved dependencies?http://groups.google.de/group/comp.programming.threads/msg/0a3cb5018b...

That was indeed the problem that motivated my post. Using a realtime
scheduler the
thread that released the mutex would acquire it again over and over.
Even if I called pthread_cond_signal while holding the mutex.

sched_yield fixed my problem with a workaround, but it was just bad
design. I needed
all the signals to be taken into account (I couldn't lost anyone) and
in this case I think I
got it right in the fixed example. Right?

http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test-ok.c

Again, thanks a lot for your help.

N.-

Markus Elfring

unread,
Feb 20, 2008, 10:13:13 AM2/20/08
to
> http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test-ok.c

Are you going to complete the error handling in the source code?

Would you also like to add any more test output that will show how the threads
will play "ping pong" with each other?
Why do you notify twice about the status change in the function "doexec" that
anything was done?

Regards,
Markus

David Schwartz

unread,
Feb 20, 2008, 2:14:20 PM2/20/08
to
On Feb 20, 5:06 am, Nelson Castillo <nelson...@gmail.com> wrote:

> That was indeed the problem that motivated my post. Using a realtime
> scheduler the
> thread that released the mutex would acquire it again over and over.
> Even if I called pthread_cond_signal while holding the mutex.

I don't understand how you could get a situation like this. If the
thread was making forward progress, why does it matter that it was
getting the mutex over and over? And if the thread couldn't make
forward progress, why wasn't blocking on something until it could?

This just seems like a basic consequence of poor design and has
nothing special to do with condition variables.

DS

Szabolcs Ferenczi

unread,
Feb 20, 2008, 2:17:48 PM2/20/08
to
On Feb 20, 2:06 pm, Nelson Castillo <nelson...@gmail.com> wrote:

> in this case I think I
> got it right in the fixed example. Right?
>
> http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test-ok.c

No, I am afraid not. The major problem is that you are trying to use
the condition variable for event signaling which is not correct. The
condition variable is there only to indicate a possible change in the
status of the shared variables. So in this example you misuse it and
it only happens that your output is what you expect but it is not
guarantied.

Here is a corrected version, at least how I would fix it. Note that
basically you need a semaphore and your program becomes much more
simple. But first the simplified shared variable version:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#define MAXWORK 1000

#define misc_die(r) \
do { \
fprintf(stderr, "Dying... %s:%d Reason: %s\n", __FILE__, __LINE__,
(r)); \
exit(1); \
} while(0)

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t check_status = PTHREAD_COND_INITIALIZER;

static void *doexec (void *arg);

void
init (pthread_t *thr)
{
pthread_attr_t thread_attr;

if (pthread_attr_init(&thread_attr))
misc_die("pthread_attr_init");

if (pthread_create(thr, &thread_attr, doexec, NULL))
misc_die("pthread_create");
}

int action = 0;
int count = 0; /* the simulated work : increment a counter */
int done = 0;

void
new_work (void)
{
pthread_mutex_lock (&mutex);
action = 1;
pthread_cond_signal(&check_status);
while (!done)
pthread_cond_wait (&check_status, &mutex);
done = 0;
pthread_mutex_unlock (&mutex);
}

static void *
doexec (void *arg)
{
while (count < MAXWORK) {
pthread_mutex_lock (&mutex);
while (!action)
pthread_cond_wait (&check_status, &mutex);
action = 0;
pthread_mutex_unlock (&mutex);

count++; /* do work */

pthread_mutex_lock (&mutex);
done = 1;
pthread_cond_signal(&check_status);
pthread_mutex_unlock (&mutex);
}

return NULL;
}

int
main (int argc, char *argv[])
{
int i;
pthread_t thr;
init(&thr);

/* do some work MAXWORK times */
for (i = 0; i < MAXWORK; ++i)
new_work ();

/* wait for the working thread */
pthread_join(thr, NULL);

fprintf(stderr, "%d\n", count);

return 0;
};

I have omitted the checking of the return values from the pthread
calls that you could solve by a macro.

Please note that the shared variables`action' and `done' are used for
communicating the events and they are used in a handshake manner. The
condition variable only signals that there is some change in the share
state space.

Also note that you can use the pthread_join for waiting for the child
thread to finish you do not need any other synchronization there.

Finally please note that the same task can be much more simple with
semaphores.

I hope this helps.

Best Regards,
Szabolcs

Nelson Castillo

unread,
Feb 20, 2008, 2:31:56 PM2/20/08
to
On Feb 20, 10:13 am, Markus Elfring <Markus.Elfr...@web.de> wrote:
> >http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test-ok.c
>
> Are you going to complete the error handling in the source code?
>
> Would you also like to add any more test output that will show how the threads
> will play "ping pong" with each other?

Hi Markus.

Done. I guess one would like to define wrappers for some of the calls
(perhaps with a macro or with inline code) to aviod IFs that harly
ever
will be true (but that could be true).

> Why do you notify twice about the status change in the function "doexec" that
> anything was done?

In main I did this:

init();
done = 0;
while (!done)
pthread_cond_wait (&cond_done, &mutex);

and the first pthread_cond_signal in do_exec is to tell the main
thread that
we are ready to do some work.

I think this is better than:

init();
usleep( ... );

because it is predictable. Right?

Regards,
N.-

Markus Elfring

unread,
Feb 20, 2008, 4:34:01 PM2/20/08
to
> and the first pthread_cond_signal in do_exec is to tell the main
> thread that we are ready to do some work.

You have not got control about which specific thread will be notified.
Would you like to consider the use of pthread_cond_broadcast() or a separate
predicate to distinguish notification receivers?

Regards,
Markus

Szabolcs Ferenczi

unread,
Feb 20, 2008, 7:06:08 PM2/20/08
to
On Feb 20, 2:06 pm, Nelson Castillo <nelson...@gmail.com> wrote:

> in this case I think I
> got it right in the fixed example. Right?
>
> http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test-ok.c

What you try here in you example is basically not correct. It is
because you try to use the condition variable for event signaling. For
event signaling, rather the semaphore can be used. Now I try to show
you how you can solve the same problem with the semaphore in a more
concise and more elegant way:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#include <semaphore.h>
#include <errno.h>

#define MAXWORK 1000
#define THREAD_SHARED 0
#define CLOSED_SEMA 0

#define CHECKED(r) check_(r, __FUNCTION__)
static inline void check_(const int rc, const char *fn)
{
if (!rc) return;
errno = EAGAIN;
perror(fn);
exit(EXIT_FAILURE);
}

static sem_t action;
static int count = 0; /* the simulated work : increment a counter */

void new_work (void)
{
CHECKED(sem_post(&action));
}

static void *doexec (void *arg)

{
while (count < MAXWORK) {
CHECKED(sem_wait(&action));


count++; /* do work */
}

return NULL;
}

int main (int argc, char *argv[])
{
int i;
pthread_t thr;

CHECKED(sem_init(&action, THREAD_SHARED, CLOSED_SEMA));
CHECKED(pthread_create(&thr, NULL, doexec, NULL));

/* do some work MAXWORK times */
for (i = 0; i < MAXWORK; ++i)
new_work ();

/* wait for the working thread */

CHECKED(pthread_join(thr, NULL));

fprintf(stderr, "%d\n", count);
return 0;
}

Here I have also checked the return value by a combination of macro
and a function.

Please note that this solution is based on the counting semaphore. If
the library only contained binary semaphore, we should have to
implement handshaking as we did in case of the shared flags.

Best Regards,
Szabolcs

Chris Thomasson

unread,
Feb 20, 2008, 11:27:37 PM2/20/08
to
"Szabolcs Ferenczi" <szabolcs...@gmail.com> wrote in message
news:d81f383b-8314-4439...@j28g2000hsj.googlegroups.com...

> > On Feb 20, 2:06 pm, Nelson Castillo <nelson...@gmail.com> wrote:

> > in this case I think I
> > got it right in the fixed example. Right?
> >
> > http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test-ok.c

> What you try here in you example is basically not correct. It is
> because you try to use the condition variable for event signaling. For
> event signaling, rather the semaphore can be used. Now I try to show
> you how you can solve the same problem with the semaphore in a more
> concise and more elegant way:

[...]

you can customize the predicates of waitable conditions anyway you want to
with condvars. Different types of event signaling logic is trivial to
implement with condvar and mutex. Why use semaphore when you can use a
condvar to block on different aspects/predicates of the state which makes up
the various specific waitable conditions...

Szabolcs Ferenczi

unread,
Feb 21, 2008, 3:35:05 AM2/21/08
to
On Feb 21, 5:27 am, "Chris Thomasson" <cris...@comcast.net> wrote:
> "Szabolcs Ferenczi" <szabolcs.feren...@gmail.com> wrote in message

No, I am afraid you cannot use condvar for that purpose because of the
spurious wakeups that may happen. Check out the documentation of it:

"When using condition variables there is always a Boolean predicate
involving shared variables associated with each condition wait that is
true if the thread should proceed. Spurious wakeups from the
pthread_cond_timedwait() or pthread_cond_wait() functions may occur.
Since the return from pthread_cond_timedwait() or pthread_cond_wait()
does not imply anything about the value of this predicate, the
predicate should be re-evaluated upon such return."
http://www.opengroup.org/onlinepubs/009695399/functions/pthread_cond_wait.html

That is why you have to use semaphore for event signaling.

Alternatively, you can use shared variables as flags but then you must
use mutex and condvar. However, the condvar is _just an optimization_
aid and it must not be used functionally such as for event signaling.
It means that, in a pre-emptive system, any correct algorithm should
work if you remove the condvar only it is not that efficient.

I have shown you example for both solutions.

Dave Butenhof

unread,
Feb 21, 2008, 8:09:09 AM2/21/08
to
Szabolcs Ferenczi wrote:
> On Feb 21, 5:27 am, "Chris Thomasson" <cris...@comcast.net> wrote:
>> "Szabolcs Ferenczi" <szabolcs.feren...@gmail.com> wrote in message
>>
>>>> On Feb 20, 2:06 pm, Nelson Castillo <nelson...@gmail.com> wrote:
>> you can customize the predicates of waitable conditions anyway you want to
>> with condvars. Different types of event signaling logic is trivial to
>> implement with condvar and mutex. Why use semaphore when you can use a
>> condvar to block on different aspects/predicates of the state which makes up
>> the various specific waitable conditions...
>
> No, I am afraid you cannot use condvar for that purpose because of the
> spurious wakeups that may happen. Check out the documentation of it:
>
> [...]

>
> That is why you have to use semaphore for event signaling.

That's silly. Did you post a news article or did you type a bunch of
text at a keyboard and submit the buffer to a news server? Both views
are rational enough, but if you can't realize they're equivalent you're
in trouble.

An "event" is just a synchronization and blocking mechanism with a
built-in predicate that's disconnected from the real application data.
There ARE times when that's exactly what you want, and that's fine. Most
of the time, this just means you have to keep two disconnected
predicates (one of which you don't manage directly) in mind at all times
or the application won't work correctly.

Of course you can't compare "event" and "condition variable" directly. A
condition variable, or something that serves the same purpose, is an
essential component of an event, or semaphore. An event or semaphore,
with whatever wildly varying semantics your precise application
requires, can be trivially constructed with a mutex, condition variable,
and predicate. You can build many other forms of synchronization as well.

And while you're in essence correct about the condition variable being
"an optimization", you can't simply remove it... you'd need to replace
it with a mutex unlock and lock. Which, on any reasonably efficient
scheduler will result in starving other threads; so an actual useful
replacement for a condition variable is substantially more complicated,
and also likely to be somewhat non-portable as you can't simply rely on
a yield.

Dave Butenhof

unread,
Feb 21, 2008, 8:11:09 AM2/21/08
to
David Schwartz wrote:
> On Feb 20, 5:06 am, Nelson Castillo <nelson...@gmail.com> wrote:
>
>> That was indeed the problem that motivated my post. Using a realtime
>> scheduler the
>> thread that released the mutex would acquire it again over and over.
>> Even if I called pthread_cond_signal while holding the mutex.
>
> I don't understand how you could get a situation like this. If the
> thread was making forward progress, why does it matter that it was
> getting the mutex over and over? And if the thread couldn't make
> forward progress, why wasn't blocking on something until it could?

Because the application was a typically brain-dead thread-per-client
server written to expect some arbitrary and impractical
application-centric notion of "fair" scheduling? It's certainly easier
if the system implements the tricky parts of your application for you!

> This just seems like a basic consequence of poor design and has
> nothing special to do with condition variables.

Indeed. ;-)

Szabolcs Ferenczi

unread,
Feb 21, 2008, 8:38:16 AM2/21/08
to
On Feb 21, 2:09 pm, Dave Butenhof <david.buten...@hp.com> wrote:
> Szabolcs Ferenczi wrote:
> > On Feb 21, 5:27 am, "Chris Thomasson" <cris...@comcast.net> wrote:
> >> "Szabolcs Ferenczi" <szabolcs.feren...@gmail.com> wrote in message
>
> >>>> On Feb 20, 2:06 pm, Nelson Castillo <nelson...@gmail.com> wrote:
> >> you can customize the predicates of waitable conditions anyway you want to
> >> with condvars. Different types of event signaling logic is trivial to
> >> implement with condvar and mutex. Why use semaphore when you can use a
> >> condvar to block on different aspects/predicates of the state which makes up
> >> the various specific waitable conditions...
>
> > No, I am afraid you cannot use condvar for that purpose because of the
> > spurious wakeups that may happen. Check out the documentation of it:
>
> > [...]
>
> > That is why you have to use semaphore for event signaling.
>
> That's silly.

Really? Good that we have some clever guys around. Then, I invite you
to publish your clever version here. I did publish here something that
you claim to be silly. Not very nice but we are certainly different.

Especially, I am curious to see your algorithm where you demonstrate
how do you use the condition variable for event signaling.

> And while you're in essence correct about the condition variable being
> "an optimization", you can't simply remove it... you'd need to replace
> it with a mutex unlock and lock.

You are right. I overlooked this issue but the main message was that
the condition variable is simply an optimization aid for the process
scheduling and it should not play any functional role.

Looking forward to seeing your clever algorithm. I am ready to learn.

Best Regards,
Szabolcs

Nelson Castillo

unread,
Feb 21, 2008, 8:45:02 AM2/21/08
to

Hello.

This test was for a timer. I also read the Szabolcs email about
semaphores and I think they wouldn't work for me. If what I included
in the example were the only code I needed to execute, I wouldn't
need a "slave" thead at all.

I needed pthread_cond_timedwait because I'm working with a timer
and the "waiting thread" can be interrupted by:

- timeout, a functions needs to be executed
- new timer (so perhaps we have to wait for less time)
- delete timer (so perhaps we no longer have to wait for the timer
we're waiting for)

And I cannot miss a single signal, because I need a timer to be
cancelled
when the function timer_cancel returns. Check timer_reset for an
example.

http://svn.arhuaco.org/svn/src/junk/trunk/threads/test_timer.c

How do you think I could design the timer with a different/better
patern?
Did I do bad design? If this is the case, I'd like to know.

So far it does what I need it to do. But I guess it can be improved.
(I haven't written the cleanup code yet, the process exits now).

Best regards,
Nelson.-

Dave Butenhof

unread,
Feb 21, 2008, 9:11:10 AM2/21/08
to
Szabolcs Ferenczi wrote:
> On Feb 21, 2:09 pm, Dave Butenhof <david.buten...@hp.com> wrote:
>> Szabolcs Ferenczi wrote:
>>> On Feb 21, 5:27 am, "Chris Thomasson" <cris...@comcast.net> wrote:
>>>> "Szabolcs Ferenczi" <szabolcs.feren...@gmail.com> wrote in message
>>>>>> On Feb 20, 2:06 pm, Nelson Castillo <nelson...@gmail.com> wrote:
>>>> you can customize the predicates of waitable conditions anyway you want to
>>>> with condvars. Different types of event signaling logic is trivial to
>>>> implement with condvar and mutex. Why use semaphore when you can use a
>>>> condvar to block on different aspects/predicates of the state which makes up
>>>> the various specific waitable conditions...
>>> No, I am afraid you cannot use condvar for that purpose because of the
>>> spurious wakeups that may happen. Check out the documentation of it:
>>> [...]
>>> That is why you have to use semaphore for event signaling.
>> That's silly.
>
> Really? Good that we have some clever guys around. Then, I invite you
> to publish your clever version here. I did publish here something that
> you claim to be silly. Not very nice but we are certainly different.
>
> Especially, I am curious to see your algorithm where you demonstrate
> how do you use the condition variable for event signaling.

You're missing the point, apparently.

An "event" cannot exist or function without some internal mechanism that
is, in essence, a condition variable. A condition variable is nothing
more than a flexible abstraction of that specific aspect of the
communication protocol embodied by event, semaphore, monitor, or various
others. The POSIX philosophy was that by exposing the generic PRIMITIVE,
applications can more easily build exactly what they need rather than
trying to warp inflexible "higher level" primitives to fit their needs.

If the "higher level" primitives you have available are already exactly
what you want, and if they perform suitably for your needs, by all means
use them. I never said you couldn't, or even shouldn't.

But in many more cases, you can use the primitives specified by POSIX,
and your own application predicate data, to build a much more specific
and efficient protocol suited to the application needs. And if you're
sharing state and making decisions about it, the predicates always
already exist in the application -- by definition. They may not be
isolated or identified, but that's simply a design problem. And if
you're using events to manage application predicates more complicated
than the state embodied in the event itself you'd almost certainly be
better off dumping that redundant state (and the event) and "rolling
your own".

All that's "silly" is your blanket statement that this can't be done,
that there's some magic inherent to "events" that cannot be implemented
by any mere mortal. But if you choose to believe that, you just go ahead.

Szabolcs Ferenczi

unread,
Feb 21, 2008, 9:36:56 AM2/21/08
to
On Feb 21, 3:11 pm, Dave Butenhof <david.buten...@hp.com> wrote:

> You're missing the point, apparently.

No, what I am missing is your code, apparently. Please mind that a
piece of code worth thousands of words.

> All that's "silly" is your blanket statement that this can't be done,
> that there's some magic inherent to "events" that cannot be implemented
> by any mere mortal. But if you choose to believe that, you just go ahead.

I have shown already that the same problem can be solved based on (1)
the combination of shared variable and condition variable or (2) based
on semaphore. Please have a look at it before you talk "silly".

Ceterum censeo, I am looking forwards to seeing your clever algorithm
where you demonstrate how do you use condition variable for event
signaling.

Best Regards,
Szabolcs

Dave Butenhof

unread,
Feb 21, 2008, 9:49:54 AM2/21/08
to
Szabolcs Ferenczi wrote:
> On Feb 21, 3:11 pm, Dave Butenhof <david.buten...@hp.com> wrote:
>
>> You're missing the point, apparently.
>
> No, what I am missing is your code, apparently. Please mind that a
> piece of code worth thousands of words.
>
>> All that's "silly" is your blanket statement that this can't be done,
>> that there's some magic inherent to "events" that cannot be implemented
>> by any mere mortal. But if you choose to believe that, you just go ahead.
>
> I have shown already that the same problem can be solved based on (1)
> the combination of shared variable and condition variable or (2) based
> on semaphore. Please have a look at it before you talk "silly".

I see. So your answer is that your statement was incorrect and you knew
that at the time you wrote it.

Then I guess we're done.

Really, if you knew it could be implemented either way, why did you say
it can't?

Just what IS your point?

Nevermind, it doesn't matter. I'm not sure I even want to know.

Szabolcs Ferenczi

unread,
Feb 21, 2008, 10:11:41 AM2/21/08
to
On Feb 21, 3:49 pm, Dave Butenhof <david.buten...@hp.com> wrote:

> Then I guess we're done.

I am afraid yes, we are done. And we can conclude that you were unable
to come up with any sensible code. Instead you ran away.

> Really, if you knew it could be implemented either way, why did you say
> it can't?

You might misunderstood something and claimed that what I have written
was silly. Check out what I have written, read it carefully, and
finally justify your claims by a sensible fragment of code.

> Just what IS your point?

My point has been communicated both by code fragments and by words.

Ceterum censeo, I am looking forwards to seeing some code from you
where you demonstrate that you can use a condition variable for event
signaling better than a semaphore.

Best Regards,
Szabolcs

Nelson Castillo

unread,
Feb 21, 2008, 11:23:32 AM2/21/08
to

Hi.

I don't think we need to do so. There is only one possible receiver
blocked waiting for
the condition.

Regards,
N.-

Dave Butenhof

unread,
Feb 21, 2008, 11:40:34 AM2/21/08
to
Szabolcs Ferenczi wrote:
> On Feb 21, 3:49 pm, Dave Butenhof <david.buten...@hp.com> wrote:
>
>> Then I guess we're done.
>
> I am afraid yes, we are done. And we can conclude that you were unable
> to come up with any sensible code. Instead you ran away.
>
>> Really, if you knew it could be implemented either way, why did you say
>> it can't?
>
> You might misunderstood something and claimed that what I have written
> was silly. Check out what I have written, read it carefully, and
> finally justify your claims by a sensible fragment of code.

I commented on a direct and unambiguous statement in your post. You can
deny it or try to hide behind spurious challenges all you want. If you
didn't mean what you said, fine; say so and move on. Otherwise all the
bluster in the world doesn't help.

Szabolcs Ferenczi

unread,
Feb 21, 2008, 11:59:25 AM2/21/08
to
On Feb 21, 5:40 pm, Dave Butenhof <david.buten...@hp.com> wrote:

> I commented on a direct and unambiguous statement in your post.

Yes, my statement was direct and unambiguous. However, you did not
commented on it but rather you claimed that it was silly.

My statement was about the fact that for event signaling you can only
use semaphore but you cannot use condition variable as it appeared to
the example attached earlier in this thread. That is direct and
unambiguous.

Apparently you did not check out anything but jumped in the middle of
a conversation with a low language.

Ceterum censeo, I am looking forward to seeing your algorithm, where
you demonstrate how do you use the condition variable for event
signaling.

Best Regards,
Szabolcs

Szabolcs Ferenczi

unread,
Feb 21, 2008, 1:33:31 PM2/21/08
to
On Feb 21, 2:45 pm, Nelson Castillo <nelson...@gmail.com> wrote:

> This test was for a timer. I also read the Szabolcs email about
> semaphores and I think they wouldn't work for me. If what I included
> in the example were the only code I needed to execute, I wouldn't
> need a "slave" thead at all.
>
> I needed pthread_cond_timedwait because I'm working with a timer
> and the "waiting thread" can be interrupted by:
>
> - timeout, a functions needs to be executed
> - new timer (so perhaps we have to wait for less time)
> - delete timer (so perhaps we no longer have to wait for the timer
> we're waiting for)

Your special problem is that there is one more reason why the
pthread_cond_timedwait can return and that is spurious wakeup. You
must handle that case also. But it practically means that you must
build your algorithm so that the pthread_cond_timedwait can legally
return almost immediately because of spurious wakeup.

On the other hand, I have already mentioned to you that you can solve
the same problem with binary semaphores. For timer purposes you can
use the mutex which is basically a binary semaphore. The advantage
from the aspects of timing is that it also has a timed out waiting
call: pthread_mutex_timedlock

If you use a mutex as a binary semaphore, you can implement your
cancellable timer like this:

...
static pthread_mutex_t action = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t done = PTHREAD_MUTEX_INITIALIZER;

static pthread_mutex_t fguard = PTHREAD_MUTEX_INITIALIZER;
static int finish = 0;

static int count = 0; /* the simulated work : increment a counter */

static int atomic_finished()
{
int r;
CHECKED(pthread_mutex_lock(&fguard));
r = finish;
CHECKED(pthread_mutex_unlock(&fguard));
return r;
}

static void atomic_set_finished()
{
CHECKED(pthread_mutex_lock(&fguard));
finish = 1;
CHECKED(pthread_mutex_unlock(&fguard));
}

void new_work (void)
{
CHECKED(pthread_mutex_unlock(&action));
CHECKED(pthread_mutex_lock(&done));
}

static void *doexec (void *arg)
{

struct timespec abstimeout;
while (1) {
calculate_timeout_value(&abstimeout, MY_TIMEOUT_VALUE);
if (pthread_mutex_timedlock(&action, &abstimeout)) {
printf("Timed out\n");
break; /* or do whatever */
}
if (atomic_finished()) break;


count++; /* do work */

CHECKED(pthread_mutex_unlock(&done));
}
return NULL;
}

int main (int argc, char *argv[])
{
int i;
pthread_t thr;

CHECKED(pthread_mutex_lock(&action));
CHECKED(pthread_mutex_lock(&done));
CHECKED(pthread_create(&thr, NULL, doexec, NULL));

/* do some work MAXWORK times */
for (i = 0; i < MAXWORK; ++i)
new_work ();

atomic_set_finished();
CHECKED(pthread_mutex_unlock(&action));

/* wait for the working thread */
CHECKED(pthread_join(thr, NULL));

fprintf(stderr, "%d\n", count);
return 0;
}

Best Regards,
Szabolcs

Nelson Castillo

unread,
Feb 21, 2008, 2:58:08 PM2/21/08
to
On Feb 21, 1:33 pm, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:

> On Feb 21, 2:45 pm, Nelson Castillo <nelson...@gmail.com> wrote:
>
> > This test was for a timer. I also read the Szabolcs email about
> > semaphores and I think they wouldn't work for me. If what I included
> > in the example were the only code I needed to execute, I wouldn't
> > need a "slave" thead at all.
>
> > I needed pthread_cond_timedwait because I'm working with a timer
> > and the "waiting thread" can be interrupted by:
>
> > - timeout, a functions needs to be executed
> > - new timer (so perhaps we have to wait for less time)
> > - delete timer (so perhaps we no longer have to wait for the timer
> > we're waiting for)
>
> Your special problem is that there is one more reason why the
> pthread_cond_timedwait can return and that is spurious wakeup. You
> must handle that case also.
> But it practically means that you must
> build your algorithm so that the pthread_cond_timedwait can legally
> return almost immediately because of spurious wakeup.

Hi Szabolcs.

while (timer_action == ACTION_NONE && (r != ETIMEDOUT && r !=
EINVAL && r != EPERM))
r = pthread_cond_timedwait(&timer_cond, &timer_mutex,
&abstimeout);

On a spurious wakeup, timer_action will be ACTION_NONE and the
pthread_cond_timedwait
will be called again. I think this is what you meant. Other functions
only change timer_action
while holding the mutex.

Regards,
Nelson.-

Markus Elfring

unread,
Feb 21, 2008, 3:03:16 PM2/21/08
to
> I don't think we need to do so.

I've got my doubts.


> There is only one possible receiver blocked waiting for the condition.

I do not see a need for double signalling on the same condition variable in this
case. I have got the impression that this is an indication for a broken software
design, isn't it? How do you think about handling of separate predicates "work
done" and "process shutdown"?

Regards,
Markus

Markus Elfring

unread,
Feb 21, 2008, 4:05:48 PM2/21/08
to
> That is why you have to use semaphore for event signaling.

I guess that we all know that semaphores and mutexes (with condition variables)
can be used to basically implement their synchronisation interfaces by each
others means. Both APIs (sem_*/pthread_*) are building blocks for higher level
abstractions.

I am unsure where the disagreement about the purpose of events in the
application for concurrent communication protocols does come from.

Regards,
Markus

Szabolcs Ferenczi

unread,
Feb 21, 2008, 4:25:02 PM2/21/08
to

OK. Now before you also try to argue against something that you did
not check abfront, just like clever guy did earlier today, please
perform the following algorithm:

1. Goto post 1 and check the example named cond-signal-test.c
2. Try to figure out what is the role of condition variable named
`cond' in that example. If you find that the condition variable `cond'
is correctly used there, please explain me why.
3. Goto post 20 and check how I fixed the code.
4. Goto post 21 and check how I solve the same with semaphore using it
for event signaling.
5. Think about what you saw and try to match with your claim that


"semaphores and mutexes (with condition variables) can be used to
basically implement their synchronisation interfaces by each others
means."

6. Please tell me what you are talking about.

Thank you.

Best Regards,
Szabolcs

Nelson Castillo

unread,
Feb 21, 2008, 5:19:03 PM2/21/08
to
On Feb 21, 3:03 pm, Markus Elfring <Markus.Elfr...@web.de> wrote:
> > I don't think we need to do so.
>
> I've got my doubts.
>
> > There is only one possible receiver blocked waiting for the condition.
>
> I do not see a need for double signalling on the same condition variable in this
> case. I have got the impression that this is an indication for a broken software
> design, isn't it?

:) Perhaps. But, let's not go philosophical here. Let's define "not
broken" as:

* works predictably
* is correct according to POSIX
* is not ugly (this is the less objective part...)

> How do you think about handling of separate predicates "work
> done" and "process shutdown"?

/* wait for the working thread */
for (i = 0; i < 100; ++i)
new_work ();

/* wait for the working thread */

Here all the work will be already done.

if (pthread_mutex_lock (&mutex))
misc_die("pthread_mutex_lock");

action = 1;
done = 0;

if (pthread_cond_signal(&cond_work))
misc_die("pthread_cond_signal");

here I have the same mutex, but a different condition variable.
I think that only one thread is waiting for an event because that's
how
i made it to be. I can only grab the mutex here if the working thread
released it with pthread_cond_timedwait.

After all this discussion, now I really understand what the man page
of
pthread_cond_signal means with:

if predictable scheduling behavior is required, then that mutex
shall be locked
by the thread calling pthread_cond_broadcast() or
pthread_cond_signal().

Still have doubts?

---

while (!done)
if (pthread_cond_wait(&cond_done, &mutex))
misc_die("pthread_cond_signal");

So this is the shutdown code. I could have replaced this one with
pthread_join, as someone suggested. I think using pthread_join is
the right thing to do here and I'll use it in the future.
I really care about test_timer.c and I will use pthread_join when I
get
to write the shutdown code.

Other that that, the code seems to be OK. I think I could have used
sem_timedwait and not pthread_cond_timedwait, but it is easier
for me to think in terms of threads and I also use Linux with NPTL,
and
I think it is faster because of the futexes (I'm not sure).

Please don't be too picky with the code of cond-signal-test-ok.c. I
only wrote it
so I could ask for help for test_timer.c (which is not done yet, it is
missing the
wrappers (to check all return values) and shutdown code. I don't think
it is polite
to ask for help with a lot of code unrelated with the issue you're
having at the
moment.

Thanks,
Nelson.-

Szabolcs Ferenczi

unread,
Feb 21, 2008, 5:38:42 PM2/21/08
to
On Feb 21, 8:58 pm, Nelson Castillo <nelson...@gmail.com> wrote:

>      while (timer_action == ACTION_NONE && (r != ETIMEDOUT && r !=
> EINVAL && r != EPERM))
>          r = pthread_cond_timedwait(&timer_cond, &timer_mutex,
> &abstimeout);
>
> On a spurious wakeup, timer_action will be ACTION_NONE and the
> pthread_cond_timedwait
> will be called again. I think this is what you meant. Other functions
> only change timer_action
> while holding the mutex.

You are right. On spurious wakeup pthread_cond_timedwait returns with
zero, according to the spec, so this part works ok. I would suggest,
however, to check for the returned zero and not for the error codes,
since the error codes can be extended or changed on other platforms.
Nevertheless the code becomes also more simple, easier to read:

while (timer_action == ACTION_NONE && r == 0) ...

So far I have dealt with your example code but I can check the timer
code if you like. I have a feeling that the shared variable state
space should be partitioned and different parts should be protected by
different mutexes. As a result you can get finer granularity in terms
of critical sections.

Best Regards,
Szabolcs

Nelson Castillo

unread,
Feb 21, 2008, 6:19:23 PM2/21/08
to
On Feb 21, 5:38 pm, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:

> On Feb 21, 8:58 pm, Nelson Castillo <nelson...@gmail.com> wrote:
>
> > while (timer_action == ACTION_NONE && (r != ETIMEDOUT && r !=
> > EINVAL && r != EPERM))
> > r = pthread_cond_timedwait(&timer_cond, &timer_mutex,
> > &abstimeout);
>
> > On a spurious wakeup, timer_action will be ACTION_NONE and the
> > pthread_cond_timedwait
> > will be called again. I think this is what you meant. Other functions
> > only change timer_action
> > while holding the mutex.
>
> You are right. On spurious wakeup pthread_cond_timedwait returns with
> zero, according to the spec, so this part works ok. I would suggest,
> however, to check for the returned zero and not for the error codes,
> since the error codes can be extended or changed on other platforms.
> Nevertheless the code becomes also more simple, easier to read:
>
> while (timer_action == ACTION_NONE && r == 0) ...

Hello Szabolcs.

I'll do it this way. Thanks.

> So far I have dealt with your example code but I can check the timer
> code if you like. I have a feeling that the shared variable state
> space should be partitioned and different parts should be protected by
> different mutexes. As a result you can get finer granularity in terms
> of critical sections.

It would be nice to know which parts can be done in a better way. (I'm
aware of the cleanup part).
Please don't tell me to use semaphores :) :)

BTW, I've noticed people assume that when they do:

if (pthread_create(..., work_func))
die(...).
do_work(...)

work_func will be executed to the point where it is ready
waiting for "do_work" (in the cases where this is the pattern).
For instance, If I need work_func to get a mutex before do_work gets
called,
I have to wait for it to be ready. Something like:

if (pthread_create(..., work_func))
die(...).
wait_for_work_func_to_be_ready_somehow();
do_work(...);

I think that doing otherwise is a bug because you depend on what the
scheduler will do.
(I think in the case of the timer, I think this is not a bad design. I
_need_ the mutex to
reach pthread_cond_timedwait so that it releases the mutex in this
point before any
other task gets the mutex).

There are a few ways of implementing that come to my mind (that could
be embedded
an initialization function):

- a semaphore (specific for this )
- a mutex (specific for this)
- a variable and ==> while (!were_ready)usleep(something).
- what I did in cond-signal-test-ok.c/test_timer.c with the condition
variable

It is not beautiful, but I think it is correct. Let me know if I'm not
right.

Regards,
N.-

Szabolcs Ferenczi

unread,
Feb 21, 2008, 7:05:23 PM2/21/08
to
On Feb 22, 12:19 am, Nelson Castillo <nelson...@gmail.com> wrote:

> It would be nice to know which parts can be done in a better way. (I'm
> aware of the cleanup part).
> Please don't tell me to use semaphores :)  :)

Ok, I will try to help in it. Anyway, do not be afraid so much about
the semaphores. Semaphores, mutexes and condition variables can be
used side by side. If something is about pure event signaling, you can
use semaphores. If something is about handling of shared variables,
especially if long term scheduling is involved, mutexes and condition
variables can be more appropriate.

All you have to do, as is the case in many other areas, is to learn
using the tools that are available. And use the most appropriate tool
wherever it is applicable.

> BTW, I've noticed people assume that when they do:
>
> if (pthread_create(..., work_func))
>   die(...).
> do_work(...)
>
> work_func will be executed to the point where it is ready
> waiting for "do_work" (in the cases where this is the pattern).
> For instance, If I need work_func to get a mutex before do_work gets
> called,
> I have to wait for it to be ready. Something like:
>
> if (pthread_create(..., work_func))
>   die(...).
> wait_for_work_func_to_be_ready_somehow();
> do_work(...);
>
> I think that doing otherwise is a bug because you depend on what the
> scheduler will do.

It is not very clear to me what is your problem here but it is mostly
possible that those people who assume such things they create the
problem themselves. It can be clear if we bring certain examples for
it. Let us look at the timer code for an example.

> (I think in the case of the timer, I think this is not a bad design. I
> _need_ the mutex to
> reach pthread_cond_timedwait so that it releases the mutex in this
> point before any
> other task gets the mutex).

As far as I could get it from the timer example, the critical region
locked by timer_mutex is much larger than necessary. For instance, the
whole timer_exec thread is locked except for the time when it is
waiting on a condition variable. The large critical region is a
problem because no matter that you give condition variable signals at
the beginning of the thread, if you do not release the critical
region, no other thread will have a chance to react. I will give you
more details about this kind of the problem later.

Best Regards,
Szabolcs

Markus Elfring

unread,
Feb 21, 2008, 7:45:39 PM2/21/08
to
> Please don't be too picky with the code of cond-signal-test-ok.c.

I might appear a bit pedantic on some details because I would like to point out
dangers from potential mistakes that are still applied to the real source files.
I guess that your source code example was useful to show a few open issues where
other software developers can also learn about relevant dependencies.

Regards,
Markus

Szabolcs Ferenczi

unread,
Feb 22, 2008, 11:30:10 AM2/22/08
to
I find it an interesting challenge to help you in improving your timer
design.

http://svn.arhuaco.org/svn/src/junk/trunk/threads/test_timer.c

Let us progress along the lines suggested by Brinch Hansen, one of the
greatest fellows in the history of concurrent programming:

"To discover a program structure ... I ask myself three questions
(1) Which activities must take place simultaneously to handle this
application?
(2) What are the major data structures needed to solve the problem on
a computer?
(3) Can these data structures be split into smaller ones by
introducing the known requirements one at a time?"
From Per Brinch Hansen, The Architecture of Concurrent Programs, 1977

It is very important to make a clear distinction between the processes
(i.e. activities) and the data structures (passive entities). I have a
feeling that it is mixed up in your existing timer implementation.

First let me summarize what I have found out from your existing timer
design. I am not focusing on the small details in the existing
implementation rather I am about to extract the overall intended
design.

You have N (i.e. 5) worker processes (created from function
timer_task) that you start up initially:

PROCESS: /worker_0/ /worker_1/ /worker_2/ /worker_3/ /worker_4/

As far as I can see, the worker processes receive and execute disjoint
jobs atomically in finite time.

You also start up a timer process (created from function timer_exec)
which is to give a trigger to the workers if the time comes to carry
out a job.

PROCESS: /timer_exe/

Finally, yet another process (role played by the main thread) creates
and supplies jobs to the timer process via function call
timer_schedule():

PROCESS: /main controller/

The main controller feeds the timer process via a pool (implemented
currently by a linked list tcl). The controller submits the
description of the job. The timer process checks the pool and
processes it by giving a signal to a ready worker to do the job and it
hands over the job details as well.

INTERACTION: /main controller/ ---submits---> |pool| <---obtains--- /
timer_exe/
INTERACTION: /timer_exe/ ---activates--->> /worker_n/

The interesting question is how would you describe by words what the
timer process is expected to do. I am afraid currently there is
something wrong about it. Currently it waits by itself until the
scheduled execution time of the first task description which is found
in the pool and then activates a worker with that job. (At least I
think the assignment of jobs and workers should happen at the timer
process and not at the time the job is created.)

Additionally, the main controller should be able to cancel or reset a
job which is in the pool but not processed yet (I am not very sure in
this requirement, it is difficult to figure out from the existing code
what is intended.)

I think this is the overall arrangement in your design. I believe
first we must make clear what are the requirements and then we can
start to change the existing design, to partition the data structures,
etc.

So the main question is how would you define the expected behaviour of
the timer_exe process. Should the timer process itself wait for the
launch time or should the workers start by delaying themselves until
the moment of time comes? Alternatively, should the timer process
apply some other algorithm, e.g. it takes the job at the time it is
planned to be executed and assigns the job to a free worker?

Further question: What do you actually want to cancel or reset? Do you
want to cancel a job being performed by a worker process or a
submitted job description from the pool. (The current implementation
does the latter.)

I am afraid there is no point of going any further with the
implementation until these questions become clear.

On the other hand, if you answer these questions, a good design is
emerging already.

Best Regards,
Szabolcs

Chris Thomasson

unread,
Feb 22, 2008, 2:31:41 PM2/22/08
to
"Szabolcs Ferenczi" <szabolcs...@gmail.com> wrote in message
news:64503bf9-69ed-40c9...@c33g2000hsd.googlegroups.com...

> On Feb 21, 2:09 pm, Dave Butenhof <david.buten...@hp.com> wrote:
> > Szabolcs Ferenczi wrote:
> > > On Feb 21, 5:27 am, "Chris Thomasson" <cris...@comcast.net> wrote:
> > >> "Szabolcs Ferenczi" <szabolcs.feren...@gmail.com> wrote in message
> >
> > >>>> On Feb 20, 2:06 pm, Nelson Castillo <nelson...@gmail.com> wrote:
> > >> you can customize the predicates of waitable conditions anyway you
> > >> want to
> > >> with condvars. Different types of event signaling logic is trivial to
> > >> implement with condvar and mutex. Why use semaphore when you can use
> > >> a
> > >> condvar to block on different aspects/predicates of the state which
> > >> makes up
> > >> the various specific waitable conditions...
> >
> > > No, I am afraid you cannot use condvar for that purpose because of the
> > > spurious wakeups that may happen. Check out the documentation of it:
> >
> > > [...]
> > >
> > > That is why you have to use semaphore for event signaling.
> >
> > That's silly.

> Really? Good that we have some clever guys around. Then, I invite you
> to publish your clever version here. I did publish here something that
> you claim to be silly. Not very nice but we are certainly different.

> Especially, I am curious to see your algorithm where you demonstrate
> how do you use the condition variable for event signaling.

You really don't know how to use a condvar and mutex to create a simple
event synchronization primitive? What about something stupid simple, like
this:
_______________________________________________________________
struct event {
int state; /* = 0 */
pthread_mutex_t mtx;
pthread_cond_t cond;
};

void event_set(event* const _this) {
pthread_mutex_lock(&_this->mtx);
_this->state = 1;
pthread_mutex_unlock(&_this->mtx);
pthread_cond_signal(&_this->cond);
}

void event_wait(event* const _this) {
pthread_mutex_lock(&_this->mtx);
while (! _this->state) {
pthread_cond_wait(&_this->cond, &_this->mtx);
}
_this->state = 0;
pthread_mutex_unlock(&_this->mtx);
}
_______________________________________________________________


That's a basic event object, analog of auto-reset event in Windows. BTW,
what type of event signaling are you referring to? Do you want an event that
never loses signals? If so, try an eventcount.

Chris Thomasson

unread,
Feb 22, 2008, 2:38:26 PM2/22/08
to

"Szabolcs Ferenczi" <szabolcs...@gmail.com> wrote in message
news:1881d8f0-f569-4393...@f47g2000hsd.googlegroups.com...

When you say "event signaling" do you really mean incrementing the value of
a semaphore? With PThreads, for say a shared queue, its better to use a
condvar. Why use a semaphore when its state is completely redundant? Instead
of using extra pointless state, why not use the queue state itself?

Chris Thomasson

unread,
Feb 22, 2008, 2:41:33 PM2/22/08
to

"Szabolcs Ferenczi" <szabolcs...@gmail.com> wrote in message
news:bfb53337-4f4a-4fdf...@64g2000hsw.googlegroups.com...

On Feb 21, 5:40 pm, Dave Butenhof <david.buten...@hp.com> wrote:

> > I commented on a direct and unambiguous statement in your post.

> Yes, my statement was direct and unambiguous. However, you did not
> commented on it but rather you claimed that it was silly.

> My statement was about the fact that for event signaling you can only
> use semaphore but you cannot use condition variable as it appeared to
> the example attached earlier in this thread. That is direct and
> unambiguous.

I suppose that you could not make the example work if the semaphore was
constructed with a mutex and condvar right? I am surprised at this
conversation you have had with David. I kind of looks like you need to learn
some more about condvars, perhaps you should purchase his book...

Chris Thomasson

unread,
Feb 22, 2008, 3:04:42 PM2/22/08
to
"Nelson Castillo" <nels...@gmail.com> wrote in message
news:55d6f4c0-450a-4f4a...@i7g2000prf.googlegroups.com...
On Feb 18, 4:54 pm, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:
> On Feb 18, 8:43 pm, Nelson Castillo <nelson...@gmail.com> wrote:
>
> > I have this source code that prints 1000 in a few desktop machines
> > (Linux NTPL, Linux 2.6.24).
>
> >http://svn.arhuaco.org/svn/src/junk/trunk/threads/cond-signal-test.c
[...]

First of all, change the 'ready' variable to volatile since you read it in
main using a loop not protected by a mutex. Second of all:
___________________________________________
void
dosignal (void)
{
pthread_mutex_lock (&cond_mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock (&cond_mutex);
sched_yield();
}

___________________________________________


In a sense, this is not signaling anything. You signal based on state shifts
that warrant a wakeup. You are setting absolutely no state, so why are you
signaling. You are completely misusing condvars! I assume that you want this
to actually signal the following wait correct?

___________________________________________
static void *
doexec (void *arg)
{
pthread_mutex_lock (&cond_mutex); /* unlocked when waiting for condition
*/

ready = 1;

while (action != 1)
{
count++;
pthread_cond_wait (&cond, &cond_mutex);
}
pthread_mutex_unlock (&cond_mutex);
pthread_detach(pthread_self());

return NULL;
}
___________________________________________


If so, here is how to get it right:


Add another variable called DO_IT, and assign it to zero:


static int DO_IT = 0;

Change your dosignal function to this:

___________________________________________
void
dosignal (void)
{
pthread_mutex_lock (&cond_mutex);
++DO_IT;
pthread_mutex_unlock (&cond_mutex);
pthread_cond_signal(&cond);
}
___________________________________________


Change your doexec function to this:


___________________________________________
static void *
doexec (void *arg)
{

pthread_mutex_lock (&cond_mutex); /* unlocked when waiting for condition
*/

ready = 1;

while (! action || DO_IT) {
count += DO_IT;
DO_IT = 0;
pthread_cond_wait(&cond, &cond_mutex);
}

pthread_mutex_unlock (&cond_mutex);
pthread_detach(pthread_self());

return NULL;
}
___________________________________________

Chris Thomasson

unread,
Feb 22, 2008, 3:08:37 PM2/22/08
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:HpednTp1Vq1ftSLa...@comcast.com...
[...]

> Add another variable called DO_IT, and assign it to zero:
>
>
> static int DO_IT = 0;


Since you start the count variable out at -1, and you want it to be 1000 at
the end of the program, you should start the variable DO_IT at 1:


static int DO_IT = 1;

>
>
>
> Change your dosignal function to this:
>
> ___________________________________________
> void
> dosignal (void)
> {
> pthread_mutex_lock (&cond_mutex);
> ++DO_IT;
> pthread_mutex_unlock (&cond_mutex);
> pthread_cond_signal(&cond);
> }
> ___________________________________________
>
>
>
>
> Change your doexec function to this:
>
>
> ___________________________________________
> static void *
> doexec (void *arg)
> {
>
> pthread_mutex_lock (&cond_mutex); /* unlocked when waiting for condition
> */
>
> ready = 1;
>
> while (! action || DO_IT) {
> count += DO_IT;
> DO_IT = 0;
> pthread_cond_wait(&cond, &cond_mutex);
> }
>
> pthread_mutex_unlock (&cond_mutex);
> pthread_detach(pthread_self());
>
> return NULL;
> }
> ___________________________________________


That will make your program print correct result. Also, why are you not
simply joining the thread? Why do you detach and call usleep? That's not
good style at all.

Chris Thomasson

unread,
Feb 22, 2008, 8:36:28 PM2/22/08
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:HpednTp1Vq1ftSLa...@comcast.com...
> "Nelson Castillo" <nels...@gmail.com> wrote in message
[...]

> Change your doexec function to this:
>
>
> ___________________________________________
> static void *
> doexec (void *arg)
> {
>
> pthread_mutex_lock (&cond_mutex); /* unlocked when waiting for condition
> */
>
> ready = 1;
>
> while (! action || DO_IT) {
> count += DO_IT;
> DO_IT = 0;


Yikes! I forgot to add the second check:

if (action) { break; }


> pthread_cond_wait(&cond, &cond_mutex);
> }
>
> pthread_mutex_unlock (&cond_mutex);
> pthread_detach(pthread_self());
>
> return NULL;
> }
> ___________________________________________


Here is corrected code:


___________________________________________


static int DO_IT = 1;

void
dosignal (void)
{
pthread_mutex_lock (&cond_mutex);
++DO_IT;
pthread_mutex_unlock (&cond_mutex);
pthread_cond_signal(&cond);
}

static void *
doexec (void *arg)
{
pthread_mutex_lock (&cond_mutex);

ready = 1;
while (! action || DO_IT) {
count += DO_IT;
DO_IT = 0;

if (action) { break; }


pthread_cond_wait(&cond, &cond_mutex);
}
pthread_mutex_unlock (&cond_mutex);
pthread_detach(pthread_self());
return NULL;
}
___________________________________________

There, sorry for any confusions!


Szabolcs Ferenczi

unread,
Feb 23, 2008, 8:40:02 AM2/23/08
to
On Feb 23, 1:36 am, "Chris Thomasson" <cris...@comcast.net> wrote:

> There, sorry for any confusions!

I am afraid there is no confusion here. People on this list used to
your buggy code already and keep ignoring it. It is not the first time
your attention is called to this fact on this forum. Everyone here
knows that your code is untested and crappy. Sorry for the bad news.

Besides, your attempt is still failing to provide a correct solution
for this simple example but I am afraid that is the default in your
case. You know, "multicore programming is hard" and you demonstrate it
too.

It is interesting to see how you and some others can make fool of
yourselves since long before you jumped into this conversation with a
lot of hybris, the correct solution was already there for this example
(see post dated Feb 20, 7:17 pm). Even an alternative solution has
been shown (see post dated Feb 21, 12:06 am). You guys should have
done nothing else but read back.

I hope I was of help, thus.

Best Regards,
Szabolcs

Chris Thomasson

unread,
Feb 23, 2008, 3:36:36 PM2/23/08
to
"Szabolcs Ferenczi" <szabolcs...@gmail.com> wrote in message
news:3909b10c-affd-47c9...@u10g2000prn.googlegroups.com...

On Feb 23, 1:36 am, "Chris Thomasson" <cris...@comcast.net> wrote:

> There, sorry for any confusions!

> > I am afraid there is no confusion here. People on this list used to
> > your buggy code already and keep ignoring it. It is not the first time
> > your attention is called to this fact on this forum. Everyone here
> > knows that your code is untested and crappy. Sorry for the bad news.

Read here:

http://groups.google.com/group/comp.programming.threads/browse_frm/thread/205dcaed77941352

Can I see some references to your code? Any articles or professors reference
your stuff? Personally, I don't want you reading my pseudo-code samples
because you won't be able to understand them. Like when you pointed out
something in Dmitriy V'jukov's spsc-lifo:

http://groups.google.com/group/comp.programming.threads/msg/17da9df4a0988d85

You saw a real scenario, but __erroneously__ thought it was a bug. This is
because you apparently don't know what linearization means wrt non-blocking
algorithms. You acted like an as$ in that post, well, what's new? You gave
no follow-up to try and explain yourself. Good job!

Then you write this:

http://groups.google.com/group/comp.programming.threads/msg/8db6658c94e958d2

And claim that a get function that returns bool is buggy or some non-sense
like that. I personally, don't think you know what your doing wrt creating
highly scaleable syncronization algorithms. You one of the guys who thinks
threads are evil right?

http://groups.google.com/group/comp.programming.threads/browse_frm/thread/b192c5ffe9b47926


> > Besides, your attempt is still failing to provide a correct solution
> > for this simple example but I am afraid that is the default in your
> > case. You know, "multicore programming is hard" and you demonstrate it
> > too.

The OP was completely misusing condvars; I made a valid correction:

___________________________________________
static int DO_IT = 1;


void
dosignal (void)
{
pthread_mutex_lock (&cond_mutex);
++DO_IT;
pthread_mutex_unlock (&cond_mutex);
pthread_cond_signal(&cond);
}


static void *
doexec (void *arg)
{
pthread_mutex_lock (&cond_mutex);
ready = 1;
while (! action || DO_IT) {
count += DO_IT;
DO_IT = 0;
if (action) { break; }
pthread_cond_wait(&cond, &cond_mutex);
}
pthread_mutex_unlock (&cond_mutex);
pthread_detach(pthread_self());
return NULL;
}
___________________________________________


Why can't you understand that! Oh yeah, I am dealing with somebody who
thinks that event objects cannot be created from a condvar.


> > It is interesting to see how you and some others can make fool of
> > yourselves

You think David Butenhof is a fool? What a minute, are you referencing the
that non-sense where you challenged him to create an event object out of a
condvar and mutex? I suggest you buy Davids book:

http://www.amazon.com/Programming-Threads-Addison-Wesley-Professional-Computing/dp/0201633922

Read it and learn something about condvars.


> > since long before you jumped into this conversation with a
> > lot of hybris, the correct solution was already there for this example
> > (see post dated Feb 20, 7:17 pm). Even an alternative solution has
> > been shown (see post dated Feb 21, 12:06 am). You guys should have
> > done nothing else but read back.

> > I hope I was of help, thus.

You helped me realize that your are either a troll, or you don't know the
basis of condvar's:

http://groups.google.com/group/comp.programming.threads/msg/a934807273c2d95b
(David notices your in the wrong and tries to help you...)


http://groups.google.com/group/comp.programming.threads/msg/7a0e9c383420d3fc
(You act like a punk, and challenge David to build a event object out of a
condvar...)


http://groups.google.com/group/comp.programming.threads/msg/6882cd76a7ec4970
(David tries to help you again.)


http://groups.google.com/group/comp.programming.threads/msg/235acc4ddd53e441
(You act like a piece of sh%t again, and make an ABSURD claim that you
cannot make a event object out of a condvar)


http://groups.google.com/group/comp.programming.threads/msg/3c017578d62e0524
(I show a simple event object build from condvar. You have not came up with
any of your smart as$ answers to that)

I conclude that your a newbie with a BAD attitude...


:^/

Chris Thomasson

unread,
Feb 23, 2008, 3:37:01 PM2/23/08
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:yvOdnaCsA_3IviLa...@comcast.com...

Where is your smart-as% answer Szabolcs? I am waiting for it.

Chris Thomasson

unread,
Feb 23, 2008, 3:55:20 PM2/23/08
to
"Szabolcs Ferenczi" <szabolcs...@gmail.com> wrote in message
news:3909b10c-affd-47c9...@u10g2000prn.googlegroups.com...

On Feb 23, 1:36 am, "Chris Thomasson" <cris...@comcast.net> wrote:

> > There, sorry for any confusions!

> I am afraid there is no confusion here. People on this list used to
> your buggy code already and keep ignoring it. It is not the first time
> your attention is called to this fact on this forum. Everyone here
> knows that your code is untested and crappy. Sorry for the bad news.

[...]

I post corrections. Here is a challenge to you, I want you to find some
algorithmic bugs in the pseudo-code samples I have posted after applying all
the corrections I document. Go for it!

:^)


This is going to be very hard because the algorithms I post are sound. The
corrections are mostly trivial typos.

Chris Thomasson

unread,
Feb 23, 2008, 10:51:27 PM2/23/08
to
"Szabolcs Ferenczi" <szabolcs...@gmail.com> wrote in message
news:a52d23f7-dd72-4a7b...@e60g2000hsh.googlegroups.com...

>I find it an interesting challenge to help you in improving your timer
> design.
>
> http://svn.arhuaco.org/svn/src/junk/trunk/threads/test_timer.c
>
> Let us progress along the lines suggested by Brinch Hansen, one of the
> greatest fellows in the history of concurrent programming:
[...]

Humm... Reading your posts, well, they make it sound like you are trying to
convince the author of the following book:

http://www.amazon.com/Programming-Threads-Addison-Wesley-Professional-Computing/dp/0201633922

that events objects cannot be constructed with condvars:

http://groups.google.com/group/comp.programming.threads/msg/7a0e9c383420d3fc

Since it "appears" that you don't know how to use condvars correctly, I
don't think you should be giving advise to anybody until you learn the
fundamentals. Before you go any further, PLEASE, explain why your point is
valid? I quote you and I now:

Chris Thomasson: "you can customize the predicates of waitable conditions

anyway you want to with condvars. Different types of event signaling logic
is trivial to implement with condvar and mutex. Why use semaphore when you
can use a condvar to block on different aspects/predicates of the state
which makes up the various specific waitable conditions... "


Szabolcs Ferenczi: "No, I am afraid you cannot use condvar for that purpose

because of the
spurious wakeups that may happen. Check out the documentation of it: "

Your statement is completely wrong, and gives great insight into your
"apparent" lack of experience. Now, why do you think condvars cannot be used
to implement event signaling schemes? I am very interested to hear your
detailed explanation.

Dmitriy V'jukov

unread,
Feb 24, 2008, 5:42:41 AM2/24/08
to
On 23 фев, 16:40, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:

> I am afraid there is no confusion here. People on this list used to
> your buggy code already and keep ignoring it. It is not the first time
> your attention is called to this fact on this forum. Everyone here
> knows that your code is untested and crappy. Sorry for the bad news.

Yeah, it's really bad news. For ones who not able to write code by
himself, for ones who not able to understand algorithms, for ones who
not able to understand other's code and for ones whose main instrument
is copy-paste.
But... you know... I'm personally not worry and not care about such
people too much. I'm not kindergarten tutor.

Dmitriy V'jukov

Chris Thomasson

unread,
Feb 24, 2008, 12:50:30 PM2/24/08
to

"Dmitriy V'jukov" <dvy...@gmail.com> wrote in message
news:1a41de30-44f5-42c6...@41g2000hsc.googlegroups.com...

I think Szabolcs is doing some trolling here. He succeeded in pissing me
off!

;^(

Dave Butenhof

unread,
Feb 24, 2008, 5:35:31 PM2/24/08
to

Yes, he's quite skilled at the art of being annoying and clearly would
like to pull the entire newsgroup down into silly games. Sounds like
someone else I used to know, actually. ;-)

I'm just going to ignore him.

Chris Thomasson

unread,
Feb 24, 2008, 5:58:16 PM2/24/08
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:d6ednRUxFvokHF3a...@comcast.com...

> "Szabolcs Ferenczi" <szabolcs...@gmail.com> wrote in message
> news:3909b10c-affd-47c9...@u10g2000prn.googlegroups.com...
> On Feb 23, 1:36 am, "Chris Thomasson" <cris...@comcast.net> wrote:
>
>> There, sorry for any confusions!
>
>> > I am afraid there is no confusion here. People on this list used to
>> > your buggy code already and keep ignoring it. It is not the first time
>> > your attention is called to this fact on this forum. Everyone here
>> > knows that your code is untested and crappy. Sorry for the bad news.
>
> Read here:
[...]

Humm. I am sorry for being so harsh. Never type when your in a foul-mood!
Very bad.


:^(

Chris Thomasson

unread,
Feb 24, 2008, 6:04:13 PM2/24/08
to

"Dave Butenhof" <david.b...@hp.com> wrote in message
news:fpsrfj$ge$1...@usenet01.boi.hp.com...

Yeah... Indeed! The dark ages...

:^0


>
> I'm just going to ignore him.

I just thought he did not like my posts about lock/wait-free programming.
Then I saw his claims on the event object, I thought well, he is trolling or
something, has to be.

Chris Thomasson

unread,
Feb 24, 2008, 10:54:05 PM2/24/08
to
"Szabolcs Ferenczi" <szabolcs...@gmail.com> wrote in message
news:4e93c09c-0ef0-448c...@e10g2000prf.googlegroups.com...

On Feb 21, 10:05 pm, Markus Elfring <Markus.Elfr...@web.de> wrote:
> > That is why you have to use semaphore for event signaling.
>
> I guess that we all know that semaphores and mutexes (with condition
> variables)
> can be used to basically implement their synchronisation interfaces by
> each
> others means. Both APIs (sem_*/pthread_*) are building blocks for higher
> level
> abstractions.
>
> I am unsure where the disagreement about the purpose of events in the
> application for concurrent communication protocols does come from.
>
> Regards,
> Markus

> OK. Now before you also try to argue against something that you did
> not check abfront, just like clever guy did earlier today, please
> perform the following algorithm:

> 1. Goto post 1 and check the example named cond-signal-test.c
> 2. Try to figure out what is the role of condition variable named
> `cond' in that example. If you find that the condition variable `cond'
> is correctly used there, please explain me why.

The OP was not making a state shift in the signal logic; I fixed that. I
think that the OP thought that you can just signal a condvar, well, that's
not right. You only signal when a state mutation warrants it. The condvar
just provides the means for a signal/broadcast, it does not maintain any
state about when an application should issue one. The critical-section
governed by the mutex contains the state which determines when a
signal/broadcast should be issued, and when a condition should be waited on
(e.g., failed predicate).


> 3. Goto post 20 and check how I fixed the code.
> 4. Goto post 21 and check how I solve the same with semaphore using it
> for event signaling.
> 5. Think about what you saw and try to match with your claim that
> "semaphores and mutexes (with condition variables) can be used to
> basically implement their synchronisation interfaces by each others
> means."

Don't try and diminish Markus's comments. Listen to me, Markus is 100%
correct, and you are apparently confused...


> 6. Please tell me what you are talking about.

You do understand that your assertions wrt semaphores and events are totally
wrong right? I am posting this to warn other readers who may think that you
know what you're talking about. You can implement condvars with semaphores,
check Alex Terekhovs algorithm. You can trivially implement semaphores and
events with condvars.


Here is pseudo-code for event and semaphore:


_______________________________________________________________
struct event {
int state; /* = 0 */
pthread_mutex_t mtx;
pthread_cond_t cond;
};

void event_set(event* const _this) {
pthread_mutex_lock(&_this->mtx);
_this->state = 1;
pthread_mutex_unlock(&_this->mtx);
pthread_cond_signal(&_this->cond);
}

void event_wait(event* const _this) {
pthread_mutex_lock(&_this->mtx);
while (! _this->state) {
pthread_cond_wait(&_this->cond, &_this->mtx);
}
_this->state = 0;
pthread_mutex_unlock(&_this->mtx);
}
_______________________________________________________________

_______________________________________________________________
struct sem {


int state; /* >= 0 */
pthread_mutex_t mtx;
pthread_cond_t cond;
};

void sem_post(sem* const _this) {
pthread_mutex_lock(&_this->mtx);
++_this->state;
pthread_mutex_unlock(&_this->mtx);
pthread_cond_signal(&_this->cond);
}

void sem_wait(sem* const _this) {


pthread_mutex_lock(&_this->mtx);
while (! _this->state) {
pthread_cond_wait(&_this->cond, &_this->mtx);
}

--_this->state;
pthread_mutex_unlock(&_this->mtx);
}
_______________________________________________________________


There you go; basic stupid simple semaphores and events from condvars.


Got it?

Markus Elfring

unread,
Feb 25, 2008, 5:30:05 AM2/25/08
to
> I am posting this to warn other readers who may think that you know
> what you're talking about.

I would like to add another technical detail because of completeness and
correctness reasons.


> You can implement condvars with semaphores, check Alex Terekhovs algorithm.
> You can trivially implement semaphores and events with condvars.

I guess that this design approach works for introductory courses on programming
for multi-threaded synchronisation. POSIX requirements will result in
restrictions what really can be used in standard compliant implementations.
The applicability is limited in the context of signal actions.
http://opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03
- sem_post() can be safely called from within signal handlers.
- pthread_*() interfaces do not belong to the list of async-signal-safe functions.

Regards,
Markus

Chris Thomasson

unread,
Feb 25, 2008, 3:46:19 PM2/25/08
to
"Markus Elfring" <Markus....@web.de> wrote in message
news:62fjm5F...@mid.individual.net...

Right; thanks. Well, I should _not_ of named the primitive: sem. Here ya go:
_______________________________________________________________
struct semaphore {


int state; /* >= 0 */
pthread_mutex_t mtx;
pthread_cond_t cond;
};

void semaphore_post(semaphore* const _this) {


pthread_mutex_lock(&_this->mtx);
++_this->state;
pthread_mutex_unlock(&_this->mtx);
pthread_cond_signal(&_this->cond);
}

void semaphore_wait(semaphore* const _this) {


pthread_mutex_lock(&_this->mtx);
while (! _this->state) {
pthread_cond_wait(&_this->cond, &_this->mtx);
}
--_this->state;
pthread_mutex_unlock(&_this->mtx);
}
_______________________________________________________________


Now there is no confusions. semaphore_post cannot be used in a signal
handler because its not on the list of compatible functions.

Markus Elfring

unread,
Feb 25, 2008, 5:30:14 PM2/25/08
to
> Now there is no confusions. semaphore_post cannot be used in a signal
> handler because its not on the list of compatible functions.

I pointed out that the implementation of the function "sem_post" must be
async-signal-safe. This software design requirement limits the usable solutions
to some degree. Condition variables and mutexes must not be called there.

The previously mentioned exchangeability of API details is not affected for
functions that will never be called in the execution context of signal actions.
Now I hope that the involved dependencies are clarified for all interested
readers on correct synchronisation.

Regards,
Markus

Szabolcs Ferenczi

unread,
Feb 26, 2008, 3:21:04 PM2/26/08
to
On Feb 22, 5:30 pm, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:

> I find it an interesting challenge to help you in improving your timer
> design.
>
> http://svn.arhuaco.org/svn/src/junk/trunk/threads/test_timer.c
>

Hi Nelson,

while waiting for your comments I have thought about your design. It
is always a good practice to brake down the problem into smaller
components. To solve your problem, you need the following elements:

Worker threads
Worker ready queue
Input buffer
Timer scheduler
Timer watchdog
Job pool

Note that these elements are already there in your timer design but
scattered all around the code.

The role of the elements can be as follows:

Worker thread: An idle worker thread joins to the worker ready queue
by putting its record there. The worker ready queue is consumed by the
timer scheduler. Whenever the timer scheduler needs to start a
scheduled job, takes the first worker from the queue and starts it
with the assigned job.

/worker/ ---insert_record---> |worker ready queue|

Worker ready queue: It is a FIFO data structure of the worker
descriptors. When a worker is ready for work it puts its descriptor
into the queue and awaits for its own activation. It is activated by a
flag in its own descriptor.

Input buffer: A proper bounded buffer of job descriptions. Capacity of
one element is enough.

Timer scheduler: It starts obtaining a job descriptor from the input
buffer. While there is no descriptor in the buffer it hangs on the get
operation. If a job is received, it puts the job into its local job
pool. Next it extracts the smallest job schedule time from the queue
and if it is time to schedule, gets a worker from the worker queue and
starts it with the job. If the smallest time to schedule is further
away, it starts the watchdog for that deadline and hangs on the input
buffer again.

|worker ready queue| <---get--- /timer scheduler/ ---get---> |input
buffer|
|job pool| <---put/get--- /timer scheduler/ ---get---> |input buffer|

Timer watchdog: It can be activated with a target time to fire. If it
was activated before, it is reactivated with the new value. When the
value expires, the watchdog puts a dummy job descriptor into the input
buffer and it is ready for the next activation.

/timer scheduler/ ---trigger--->> /timer watchdog/ ---put---> |input
buffer|

Job pool: A private data structure of the timer scheduler, so it cam
be a simple set. It needs no protection for concurrent access.

That is it. Simple, isn't it?

A refinement can be to make the worker pools expandable since it may
happen that all the workers are busy and the timer scheduler should
activate the next job. Well, one option is that the timer scheduler
abandons the job with a logging message but more appropriate would be
to create one more worker in that situation if the resources are
available for it.

The nice thing about this proposed arrangement is that the
responsibilities are well separated, so the elements are relatively
simple. The old principle of divide et impera is applied here. You can
derive the elements from your existing application or you can build
them from scrach using e.g. test driven development method. If you
have the elements together with their unit tests, integration of them
will be very easy.

How do you like it?

Best Regards,
Szabolcs

Nelson Castillo

unread,
Feb 27, 2008, 11:57:45 AM2/27/08
to
On Feb 26, 3:21 pm, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:
(cut)

> The nice thing about this proposed arrangement is that the
> responsibilities are well separated, so the elements are relatively
> simple. The old principle of divide et impera is applied here. You can
> derive the elements from your existing application or you can build
> them from scrach using e.g. test driven development method. If you
> have the elements together with their unit tests, integration of them
> will be very easy.
>
> How do you like it?

Hi there.

Thanks a lot for your suggestions. I won't be able to implement them
anytime soon. I agree with you most of what you said.

Sometimes "worse is better". I mean, I only need to use about
3 simultaneous timers and the code is working now and under
testing. If I introduce changes now I can introduce bugs, too.

So I hope I can revisit the timer again and make it cleaner
when I don't have a deadline to meet.

Today the timer is just part of a bigger project and I don't have
the resources to fix something that isn't a bug. Not yet...

Regards,
N.-

PS: Thanks a lot to all who helped.

Szabolcs Ferenczi

unread,
Mar 4, 2008, 7:43:28 PM3/4/08
to

It is a pity that you do not have time for it because it just happens
to work for that tuned test you came up with. If you remove the
delays, for instance, it immediately fails.

Nevertheless, I am ready to help anyone who has any problem with multi-
threaded designs. It is my passion to improve the design of concurrent
programs.

So, any time you feel like you would need some help for the
architecture of your multi-threaded program, just drop me a mail.

Best Regards,
Szabolcs

rfis...@gmail.com

unread,
Mar 12, 2008, 7:44:06 PM3/12/08
to
On 23 Feb, 14:40, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:

> It is interesting to see how you and some others can make fool of


> yourselves since long before you jumped into this conversation with a
> lot of hybris,

Good call - Hybris was an excellent vertical shooter for the Amiga.
Cool power ups, rocking music, just... canonical. Hubris, on the other
hand is the fatal flaw of excessive pride. Etymologically, it probably
would've been more correct to import the ancient greek ὕβρις into
english as "hybris" as was done in some other languages, but "hubris"
reflected the academic mores of the time and now we're stuck with it.
It's nobody's fault, so I suggest we all just take a deep breath,
fire up some Hybris and get on with blasting those aliens,
canonically.

RF

rfis...@gmail.com

unread,
Mar 12, 2008, 9:06:52 PM3/12/08
to
On 23 Feb, 21:36, "Chris Thomasson" <cris...@comcast.net> wrote:

[...]

> Can I see some references to your code? Any articles or professors reference
> your stuff?

Dear Chris, are you implying that there is some other more scholarly
and
refined electronic thread forum on which you publish carefully drafted
and proof read
posts? You must be, because there is no way in the world that any
white bearded
professor emeritus, egregious holder of the Lucasian Chair of Multiple
Computings
would ever, ever, ever knowingly copy and paste any part of your
emoticon infested,
uh, outpourings on c.p.t. into one of their erudite discourses.

Do not despair, however, here are a few tips for increasing the
likelihood of it happening:

- Try not to post links. No-one follows them. How much sense does
your average
post make in light of this? Write a summary instead.

- Re-read your posts at least once to weed out obvious errors.

- Try to avoid responding to your own posts.

- No emoticons, ever. Not even if you're feeling perplexed.

- Pass that messy, chicken scratchy code of yours through a compiler
once in a while
and maybe even try running it. That way we don't have to look at
your endless
corrections.

- Your = possessive pronoun. You're = you are

- Their = possessive pronoun. They're = they are

- Try to swear a little less. Even though you cover key vowels with
percent signs,
we still know you're swearing, and so does Prof. Methuselah. He's
no prude, but
"hol@y sh%t-m#ther" probably jars with the tone of his latest
paper.

- Last but not least, take a leaf out of the book of the senators of
the list. Every
single post they make is polished and perfect, ready to be
published, missing
only the ISBN, even when they're only chiming in to ably cane some
fools.
When they do finally go to talk asynchronous pipes with W.R.
Stevens it's going
to take one person all of 5 minutes on usenet to put that
posthumous book together.
Don't you think that's worth emulating?

With much love,
RF.

Chris Thomasson

unread,
Mar 12, 2008, 11:49:43 PM3/12/08
to

<rfis...@gmail.com> wrote in message
news:a42bb464-fb7d-4b39...@e60g2000hsh.googlegroups.com...

> On 23 Feb, 21:36, "Chris Thomasson" <cris...@comcast.net> wrote:
>
> [...]
>
>> Can I see some references to your code? Any articles or professors
>> reference
>> your stuff?
>
> Dear Chris,
[...]

http://groups.google.com/group/comp.programming.threads/browse_frm/thread/205dcaed77941352

Chris Thomasson

unread,
Mar 13, 2008, 12:05:29 AM3/13/08
to
<rfis...@gmail.com> wrote in message
news:a42bb464-fb7d-4b39...@e60g2000hsh.googlegroups.com...
> On 23 Feb, 21:36, "Chris Thomasson" <cris...@comcast.net> wrote:
>
> [...]
>
>> Can I see some references to your code? Any articles or professors
>> reference
>> your stuff?
>
[...]

> - Pass that messy, chicken scratchy code of yours through a compiler
> once in a while
> and maybe even try running it. That way we don't have to look at
> your endless
> corrections.


[...]


Right. I do not bother to pass the code I type into the newsreader to a
compiler. I expect you to be able to understand the basic concepts. Anyway,
here is a VERY small collection of some code you can compile:


http://appcore.home.comcast.net/~appcore/misc/winsync_v0001_rwmutex_hpp.html

http://appcore.home.comcast.net/~appcore/misc/winsync_v0001_evcount_hpp.html

http://appcore.home.comcast.net

http://groups.google.com/group/comp.programming.threads/browse_frm/thread/15e79134577d3e98

http://home.comcast.net/~vzoom/demos/pc_sample.c


Do you know what to do with those? Please ask if you need help; seriously, I
love to spread knowledge.


Read here:

http://groups.google.com/group/comp.programming.threads/msg/365d99f008ce1998
(READ ALL!)


read here for one of the fastest memory allocator algorithms out there:

http://groups.google.com/group/comp.arch/browse_frm/thread/24c40d42a04ee855


some more:

http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/65c9c2673682d4cf

https://coolthreads.dev.java.net/
(vZOOM one of the winners!)

http://groups.google.com/group/comp.programming.threads/browse_frm/thread/e0c011baf08844c4

http://groups.google.com/group/comp.programming.threads/msg/d6861df0fbf353d6

http://groups.google.com/group/comp.arch/browse_frm/thread/91cb3fbfa2eb362a


Heck! I could go on and on... For whatever reason, my work gets noticed by
more people than you would ever know about simply because I get my private
e-mails, you don't.


I have several other people interested in creating articles which reference
my work...


Please calm down and try an open your mind. Lock/Wait-Free works, as does
lock-based algorithms. So be it.

Got it?


:^)

Chris Thomasson

unread,
Mar 13, 2008, 12:09:47 AM3/13/08
to
"Chris Thomasson" <cri...@comcast.net> wrote in message
news:S-WdnZT1G-yJNUXa...@comcast.com...

> <rfis...@gmail.com> wrote in message
> news:a42bb464-fb7d-4b39...@e60g2000hsh.googlegroups.com...
>> On 23 Feb, 21:36, "Chris Thomasson" <cris...@comcast.net> wrote:
>>
>> [...]
>>
>>> Can I see some references to your code? Any articles or professors
>>> reference
>>> your stuff?
>>
> [...]
>> - Pass that messy, chicken scratchy code of yours through a compiler
>> once in a while
>> and maybe even try running it. That way we don't have to look at
>> your endless
>> corrections.
>
>
> [...]
>
>
> Right. I do not bother to pass the code I type into the newsreader to a
> compiler. I expect you to be able to understand the basic concepts.
> Anyway, here is a VERY small collection of some code you can compile:
>
>
> http://appcore.home.comcast.net/~appcore/misc/winsync_v0001_rwmutex_hpp.html
>
> http://appcore.home.comcast.net/~appcore/misc/winsync_v0001_evcount_hpp.html
>
> http://appcore.home.comcast.net
>
> http://groups.google.com/group/comp.programming.threads/browse_frm/thread/15e79134577d3e98
>
> http://home.comcast.net/~vzoom/demos/pc_sample.c
>
>
> Do you know what to do with those? Please ask if you need help; seriously,
> I love to spread knowledge.
[...]

I know you can put all of those primitives to good use; I was being
sarcastic with you. Sorry about that.

Chris Thomasson

unread,
Mar 13, 2008, 12:13:13 AM3/13/08
to

Chris Thomasson

unread,
Mar 13, 2008, 12:25:28 AM3/13/08
to

"Chris Thomasson" <cri...@comcast.net> wrote in message
news:y4mdnTdzAoX_OUXa...@comcast.com...


http://209.85.173.104/search?q=cache:JRTk2SzLVvUJ:www.cs.nyu.edu/artg/internet/Spring2006/lectures/DavidBuksbaum-BuildingHighThroughputMulti-threadedServersInCSharpAndDotNet.ppt+%22David+Buksbaum%22+appcore&hl=en&ct=clnk&cd=2&gl=us

This is the slide-show for NYU Spring 2006 lecture by David Buksbaum who
is/was Senior Vice President at Citadel Investment Group, LLC


Why should he reference my work? Educate me please!?

Chris Thomasson

unread,
Mar 13, 2008, 12:37:51 AM3/13/08
to

<rfis...@gmail.com> wrote in message
news:b61fbe01-1633-4212...@e25g2000prg.googlegroups.com...

On 23 Feb, 14:40, Szabolcs Ferenczi <szabolcs.feren...@gmail.com>
wrote:

> > It is interesting to see how you and some others can make fool of
> > yourselves since long before you jumped into this conversation with a
> > lot of hybris,

> Good call -

[...]

Well, consider this:

http://groups.google.com/group/comp.programming.threads/msg/fc1e13463a9ecb43

http://groups.google.com/group/comp.programming.threads/msg/fc1e13463a9ecb43

http://groups.google.com/group/comp.programming.threads/msg/a934807273c2d95b

Szabolcs makes very erroneous claims about POSIX Threading on purpose:

http://groups.google.com/group/comp.programming.threads/msg/6fba67075f21ca2f

http://groups.google.com/group/comp.programming.threads/msg/7af388f2fd073275

I think he trolls those retarded claims to stir the pot and make things
lively... Perhaps... Well, my favorite is when he claimed that condvars are
not designed to signal events. WOW!

Too funny.

:^)

Chris Thomasson

unread,
Mar 13, 2008, 12:57:25 AM3/13/08
to

<rfis...@gmail.com> wrote in message
news:a42bb464-fb7d-4b39...@e60g2000hsh.googlegroups.com...

> On 23 Feb, 21:36, "Chris Thomasson" <cris...@comcast.net> wrote:
>
> [...]
>
[...]

> - Try not to post links.

Sorry for the swift flurry of posts, but I am "fired up" for some reason...
Perhaps just another basic trolling attempt gone successful, well, shi%!

:^D


> No-one follows them.

Good to hear that you actually do represent everybody: You imply that no-one
follows links to Google groups... Just thought I should infrom you that
NO-ONE == EVERYONE!

Yikes!

;^D


> How much sense does your average
> post make in light of this? Write a summary instead.

[...]

I REALLY like to type code sketches in the newsreader. If that makes
somebody __VERY__ angry, well, I suggest that they open their medicine
cabinet and take 10-20mgs of their leftover chlorpromazine and realize that
this is USENET...

Dmitriy V'jukov

unread,
Mar 13, 2008, 6:20:17 AM3/13/08
to
On Mar 13, 7:25 am, "Chris Thomasson" <cris...@comcast.net> wrote:
> "Chris Thomasson" <cris...@comcast.net> wrote in message
>
> news:y4mdnTdzAoX_OUXa...@comcast.com...
>
>
>
> > <rfist...@gmail.com> wrote in message

> >news:a42bb464-fb7d-4b39...@e60g2000hsh.googlegroups.com...
> >> On 23 Feb, 21:36, "Chris Thomasson" <cris...@comcast.net> wrote:
>
> >> [...]
>
> >>> Can I see some references to your code? Any articles or professors
> >>> reference
> >>> your stuff?
>
> >> Dear Chris,
> > [...]
>
> >http://groups.google.com/group/comp.programming.threads/browse_frm/th...
>
> http://209.85.173.104/search?q=cache:JRTk2SzLVvUJ:www.cs.nyu.edu/artg...

>
> This is the slide-show for NYU Spring 2006 lecture by David Buksbaum who
> is/was Senior Vice President at Citadel Investment Group, LLC
>
> Why should he reference my work? Educate me please!?

There is also reference in Wikipedia:
http://en.wikipedia.org/wiki/Lock-free_and_wait-free_algorithms

And "Multiple Approaches to Multithreaded Applications" on Intel site:
http://softwarecommunity.intel.com/articles/eng/1664.htm
AppCore library is the only referenced lock-free library with the
words:
"A number of other examples of lock-free programming are also
available online, including Chris Thomasson's extensive list of
algorithms supporting the idea"

Dmitriy V'jukov

rfis...@gmail.com

unread,
Mar 13, 2008, 8:57:08 AM3/13/08
to
On 13 Mar, 05:37, "Chris Thomasson" <cris...@comcast.net> wrote:
> <rfist...@gmail.com> wrote in message

> > > lot ofhybris,


> > Good call -
>
> [...]
>
> Well, consider this:

No, no, Chris - you're confused. I was talking about this:
http://www.youtube.com/watch?v=Oa-Ws6BT7-M&feature=related

[...]

> Szabolcs makes very erroneous claims about POSIX Threading on purpose:

NO! Does he!? In that case, consider this:
http://xkcd.com/386/

RF

rfis...@gmail.com

unread,
Mar 13, 2008, 9:13:27 AM3/13/08
to
On 13 Mar, 05:57, "Chris Thomasson" <cris...@comcast.net> wrote:

> Sorry for the swift flurry of posts, but I am "fired up" for some reason...
> Perhaps just another basic trolling attempt gone successful, well, shi%!

See? That's what I'm talking about. In response to some light
criticism you
churned out seven "and another thing!" type replies over the course of
an hour.
There's no way you got anything useful done in that hour and we got
yet another
content-free c.p.t digest. Why not work on your signal to noise ratio?
I understand
that you use this ng as a sort of public, thinking-out-loud scratch
pad, and if that
gets you useful feedback from others, then great, carry on with that.
But at the
same time try a bit of restraint. Abundantly quoting yourself,
replying to yourself
instead of thinking beforehand, engaging in cock slapping "most
quoted"
contests and insistently and condescendingly correcting the wrong, the
stupid
and the terminally touchy does nothing to advance the state of the art
and only
decreases the utility of the ng. Or let me put it this way: if you cut
back on the
latter, you could spend more time doing the former, that is, typing
code into
your newsreader. Put in perspective it seems the lesser of the evils.

[...]

> I REALLY like to type code sketches in the newsreader. If that makes
> somebody __VERY__ angry, well, I suggest that they open their medicine
> cabinet and take 10-20mgs of their leftover chlorpromazine and realize that
> this is USENET...

So it's wrong of me to expect any kind of editorial standards?
Ok, that sounded way more naive than I meant it to, but consider
that while this may be usenet and wha-hey! anything goes, this
ng is read by your peers and by the folk who invented your trade
and taught it to you, and by not thinking before you post you fail
to show them the respect they deserve.

RF

Chris Thomasson

unread,
Mar 13, 2008, 3:35:14 PM3/13/08
to

<rfis...@gmail.com> wrote in message
news:e7da191d-514c-415d...@e60g2000hsh.googlegroups.com...

LOL! :^D

Chris Thomasson

unread,
Mar 13, 2008, 3:38:22 PM3/13/08
to
<rfis...@gmail.com> wrote in message
news:81b99cd2-a166-4d05...@13g2000hsb.googlegroups.com...

> On 13 Mar, 05:57, "Chris Thomasson" <cris...@comcast.net> wrote:
>
>> Sorry for the swift flurry of posts, but I am "fired up" for some
>> reason...
>> Perhaps just another basic trolling attempt gone successful, well, shi%!
>
> See? That's what I'm talking about. In response to some light
> criticism you
> churned out seven "and another thing!" type replies over the course of
> an hour.
> There's no way you got anything useful done in that hour and we got
> yet another
> content-free c.p.t digest. Why not work on your signal to noise ratio?

Yeah. I definitely need to work on coalescing multiple posts into one.


> I understand
> that you use this ng as a sort of public, thinking-out-loud scratch
> pad, and if that
> gets you useful feedback from others, then great, carry on with that.
> But at the
> same time try a bit of restraint. Abundantly quoting yourself,
> replying to yourself
> instead of thinking beforehand, engaging in cock slapping "most
> quoted"
> contests and insistently and condescendingly correcting the wrong, the
> stupid
> and the terminally touchy does nothing to advance the state of the art
> and only
> decreases the utility of the ng. Or let me put it this way: if you cut
> back on the
> latter, you could spend more time doing the former, that is, typing
> code into
> your newsreader. Put in perspective it seems the lesser of the evils.

Good points.


> [...]
>
>> I REALLY like to type code sketches in the newsreader. If that makes
>> somebody __VERY__ angry, well, I suggest that they open their medicine
>> cabinet and take 10-20mgs of their leftover chlorpromazine and realize
>> that
>> this is USENET...
>
> So it's wrong of me to expect any kind of editorial standards?
> Ok, that sounded way more naive than I meant it to, but consider
> that while this may be usenet and wha-hey! anything goes, this
> ng is read by your peers and by the folk who invented your trade
> and taught it to you, and by not thinking before you post you fail
> to show them the respect they deserve.

Yikes!

0 new messages