pthreadon_sleepon_signal(): works as advertised?

Hello QNXers,

I am trying to coordinate data transfer between two threads using
pthread_sleepon_* functions. My starting point is the discussion
about sleepon locks in Ch. 1 of Rob Krten’s book “Getting Started with
QNX Neutrino2” including default attributes of the threads.

The main mechanism is the blocking of one thread by a call to
pthread_sleepon_wait() until the other thread wakens it by a
pthread_sleepon_signal(). From my first attempts at this
implementation, it appears that the _signal function in the active
thread is not causing the blocked thread to wake up.

  1. Is there a known problem with pthread_sleepon_signal()?

For the morbidly curious, here’s the abridged version of my current
code (extended a bit from Krten’s example):

volatile char line_data_ready = 0; //start with empty buffer

main(): {
pthread_create(&recv_tid, NULL, &recv_lines, &recv_arg);
pthread_create(&send_tid, NULL, &send_lines, &send_arg):

<pthread_join()s occur next>
}

recv_lines():
while( ) {
pthread_sleepon_lock()
while(!line_data_ready)
pthread_sleepon_wait(&line_data_ready)
printf(“SCORE!”)
line_data_ready = 0;
pthread_sleepon_signal(&line_data_ready) // notify send_lines()
pthread_sleepon_unlock()
}

send_lines()
while( ) {
pthread_sleepon_lock()
while(line_data_ready)
pthread_sleepon_wait(&line_data_ready)
printf(“SEND MORE”)
sleep()
line_data_ready = 1
pthread_sleepon_signal(&line_data_ready) //notify recv_lines()
pthread_sleepon_unlock()
}

My understanding is that the _signal() call should awaken the other
thread but I only see one “SEND MORE” and pidin indicates that each
thread is in the CONDVAR state and blocked on b034b2e0.

  1. What is b034b230? (It’s not the address of line_data_ready)

Gratefully yours,

Bob Bottemiller
Stein.DSI/Redmond, WA USA

send_lines()
while( ) {
pthread_sleepon_lock()
while(line_data_ready)
pthread_sleepon_wait(&line_data_ready)
printf(“SEND MORE”)
sleep()
line_data_ready = 1
pthread_sleepon_signal(&line_data_ready) //notify recv_lines()
pthread_sleepon_unlock()

^^^^^^^^^^^^^^^^^^^^^^^^^^^

Aren’t you going to need to unlock prior to signalling ?

Sorry, I read you post too quickly.

Here is some source that works the way I think you intend it to.

Hello Rennie,

Thanks for looking into this behavior for me. I added that sleep(1)
line in send_lines() and, yes, it gave the desired result. Now it’s a
puzzle as to why the sleep() is needed – it certainly isn’t desirable
to pad out quick-response code with magic sleep()s. (Although I have
inspected multithreaded C++ code for Windows NT with plenty of
strategically-placed sleep() calls. The embedded comments sometimes
noted “…don’t know why this works but it is necessary – don’t
remove.”)

Another little puzzle. I substituted the pthread_sleepon_broadcast()
call for the pthread_sleepon_signal() call. That too – with no
sleep(1) – resulted in the desired cooperative behavior. Oh, well,
at least I can move on to the next development step.

Thanks again,

On Thu, 15 Nov 2001 11:39:55 -0800, Rennie Allen <rallen@csical.com>
wrote:

This is a multi-part message in MIME format.
--------------090206060303060702000005
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Sorry, I read you post too quickly.

Here is some source that works the way I think you intend it to.

--------------090206060303060702000005
Content-Type: text/plain;
name=“sleepon.c”
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename=“sleepon.c”

#include <stdio.h
#include <pthread.h

int line_data_ready=0;

int recv_lines(void *dummy)
{
while(1) {
pthread_sleepon_lock();
while(!line_data_ready)
pthread_sleepon_wait(&line_data_ready);
printf(“SCORE!\n”);
line_data_ready = 0;
pthread_sleepon_signal(&line_data_ready);
pthread_sleepon_unlock();
}
}

int send_lines(void *dummy)
{
while(1) {
pthread_sleepon_lock();
while(line_data_ready)
pthread_sleepon_wait(&line_data_ready);
printf(“SEND MORE\n”);
line_data_ready = 1;
pthread_sleepon_signal(&line_data_ready);
pthread_sleepon_unlock();
sleep(1);
}
}

main()
{
pthread_t recv_tid,send_tid;
int rc;
int recv_arg,send_arg;

pthread_create(&recv_tid, NULL, &recv_lines, &recv_arg);
pthread_create(&send_tid, NULL, &send_lines, &send_arg);

pthread_join(recv_tid, &rc);
pthread_join(send_tid, &rc);
}

--------------090206060303060702000005–

H

Bob Bottemiller
Stein.DSI/Redmond, WA USA

Bob Bottemiller <bob.bottemiller@deletefmcti.com> wrote:

Hello Rennie,

Thanks for looking into this behavior for me. I added that sleep(1)
line in send_lines() and, yes, it gave the desired result. Now it’s a
puzzle as to why the sleep() is needed – it certainly isn’t desirable
to pad out quick-response code with magic sleep()s. (Although I have
inspected multithreaded C++ code for Windows NT with plenty of
strategically-placed sleep() calls. The embedded comments sometimes
noted “…don’t know why this works but it is necessary – don’t
remove.”)

Another little puzzle. I substituted the pthread_sleepon_broadcast()
call for the pthread_sleepon_signal() call. That too – with no
sleep(1) – resulted in the desired cooperative behavior. Oh, well,
at least I can move on to the next development step.

If you put printf() in the while () sleepon_wait() loop, you will know
exactly what happened.

Usually it is:

  1. recever wait;

  2. sender hold the sleepon mutex (lock);
    set line_data_ready = 1;
    sleepon_signal();
    /* note at this moment the receiver can wake up,
    it waiting for sender to release the lock
    */
    sleepon_unlock();

  3. now, sender loop back doing the
    sleepon_lock();

Both receiver and sender are try to get the lock,
if the receiver got it, then it works as you expect.
(that’s why put a sleep() in sender after unlock()
makes it work, that is, sender let receiver to get
the lock. But as you can guess, this is not reliable)

If the sender got the lock AGAIN, can you image what
will happen? send go into sleepon_wait(), and nobody
sleepon_signal() any more;

I think have sender and receiver waiting for different value
(line_no_data). and the signal() different value is the reliable
way to solve your problem.

-xtang

Thanks again,

On Thu, 15 Nov 2001 11:39:55 -0800, Rennie Allen <> rallen@csical.com
wrote:

This is a multi-part message in MIME format.
--------------090206060303060702000005
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Sorry, I read you post too quickly.

Here is some source that works the way I think you intend it to.

--------------090206060303060702000005
Content-Type: text/plain;
name=“sleepon.c”
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename=“sleepon.c”

#include <stdio.h
#include <pthread.h

int line_data_ready=0;

int recv_lines(void *dummy)
{
while(1) {
pthread_sleepon_lock();
while(!line_data_ready)
pthread_sleepon_wait(&line_data_ready);
printf(“SCORE!\n”);
line_data_ready = 0;
pthread_sleepon_signal(&line_data_ready);
pthread_sleepon_unlock();
}
}

int send_lines(void *dummy)
{
while(1) {
pthread_sleepon_lock();
while(line_data_ready)
pthread_sleepon_wait(&line_data_ready);
printf(“SEND MORE\n”);
line_data_ready = 1;
pthread_sleepon_signal(&line_data_ready);
pthread_sleepon_unlock();
sleep(1);
}
}

main()
{
pthread_t recv_tid,send_tid;
int rc;
int recv_arg,send_arg;

pthread_create(&recv_tid, NULL, &recv_lines, &recv_arg);
pthread_create(&send_tid, NULL, &send_lines, &send_arg);

pthread_join(recv_tid, &rc);
pthread_join(send_tid, &rc);
}

--------------090206060303060702000005–

H
Bob Bottemiller
Stein.DSI/Redmond, WA USA

As Xiaodan suggests, the “problem” is the triviality of the example you
provided. The sleep is necessary to insure that the reader thread get’s
scheduled, so that it can acquire the sleepon lock before the writer. A
typical “real” situation (and probably a better example) might be a
shared queue where one thread is reading from a queue and the other is
writing to the queue (the reader would wait for queue_not_empty, and the
writer would wait for queue_not_full).

As Xiaodan states, this code is also unreliable since it depends on the
fact that your reader thread will be scheduled within the 1 second that
the writer waits (this number is so large, that it is almost certainly
always going to be true - but with smaller time periods this may not be
the case).

I have attached a still contrived, but more illustrative, example (in
the spirit of your original), which uses no sleep().

btw: as can be seen (in this trivial example - where there are only two
threads, and the semantics of the reader are simply to acknowledge that
the writer wrote something), there is no requirement to re-check the
predicate when using pthread_sleepon_signal. All of this information is
available in the documentation.

On Fri, 16 Nov 2001 01:09:30 GMT, bob.bottemiller@deletefmcti.com (Bob
Bottemiller) wrote:

(snip old content)

Thanks Xiaodan and Rennie for taking the time to explain the details.
Now I understand.


Bob Bottemiller
Stein.DSI/Redmond, WA USA