pthread_cond_signal() has no effect
"Dr. Uwe Girlich" <[email protected]>
| Newsgroups | gmane.linux.ngpt.devel |
|---|---|
| Message-ID | <[email protected]> |
Hello! There is an error in the NGPT pthread_cond_signal() handling. If there are several (n) waiters on a conditional variable and the wakeup thread calls fast n times pthread_cond_signal(), only one of the waiter threads will end its pthread_cond_wait(). 2 things to note: * Process shared objects use fuxex functionality, which works correctly. * If there is a delay between the pthread_cond_signal() calls, so that the first thread can end its pthread_cond_wait() until the wakeup thread calls pthread_cond_signal() again, it works too. So I come to the conclusion: process private conditional variables have a problem, when the scheduler does not schedule the just woken up thread. The attached mini test program demonstrates the wrong behaviour. Without any arguments, the second thread does not wake up. With -s1, it uses shared objects and it works. With -w1, it uses sleep(1) between pthread_cond_signal() calls and it works too. Bye, Uwe -- Dr. Uwe Girlich email: [email protected] Philosys Software GmbH www: www.philosys.de Edisonstrasse 6 phone: +49 89 321407-44 D-85716 Unterschleissheim fax: +49 89 321407-12
signal_test.c
(text/plain, 3.7 KB)
#include <pthread.h>
#include <stdlib.h>
int opt_threads = 2;
int opt_wait = 0;
int opt_shared = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
int value = 0;
#define errorout(x) if (error != 0) { fprintf(stderr,x, error); goto out; }
void
usage(char* progname)
{
fprintf(stderr,"%s: pthread_cond_signal() test\n", progname);
fprintf(stderr,"-t<num>\tstart <num> threads (default 2)\n");
fprintf(stderr,"-w<num>\twait (<num>!=0) or don't wait (<num>==0, default) between cond_signal()\n");
fprintf(stderr,"-s<num>\tuse shared (<num>!=0) or not shared (<num>==0, default) objects\n");
fprintf(stderr,"-h\tthis help\n");
exit(1);
}
void*
thread_main(void* args)
{
int *result = NULL;
int error;
fprintf(stderr,"tid %d running\n", (int)pthread_self());
error = pthread_mutex_lock(&mutex);
errorout("pthread_mutex_lock()=%d\n");
if (value == 0) {
fprintf(stderr, "tid %d, value==%d => cond_wait()...\n",
(int)pthread_self(), value);
error = pthread_cond_wait(&cond, &mutex);
errorout("pthread_cond_wait()=%d\n");
fprintf(stderr,"tid %d, value==%d, cond_wait() ended\n",
(int)pthread_self(), value);
}
value--;
fprintf(stderr,"tid %d, reduced value==%d\n",
(int)pthread_self(), value);
error = pthread_mutex_unlock(&mutex);
errorout("pthread_mutex_unlock()=%d\n");
sleep(1);
out:
pthread_exit(result);
return result;
}
int
main(int argc, char** argv)
{
int error = 0;
int c;
pthread_mutexattr_t mattr;
pthread_condattr_t cvattr;
int i;
pthread_t *td;
while ((c = getopt(argc, argv, "t:w:s:h")) != -1) {
switch(c) {
case 't': opt_threads = atoi(optarg); break;
case 'w': opt_wait = atoi(optarg); break;
case 's': opt_shared = atoi(optarg); break;
case 'h': usage(argv[0]); break;
case ':':
fprintf(stderr,"Option -%c requires an operand\n", optopt);
usage(argv[0]);
break;
case '?':
fprintf(stderr, "Unrecognized option: -%c\n", optopt);
usage(argv[0]);
break;
}
}
fprintf(stderr,"#threads per process: %d\n", opt_threads);
fprintf(stderr,"wait between signals: %d\n", opt_wait);
fprintf(stderr,"shared objects : %d\n", opt_shared);
error = pthread_mutexattr_init(&mattr);
errorout("pthread_mutexattr_init = %d\n");
if (opt_shared) {
error = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
errorout("pthread_mutexattr_setpshared = %d\n");
}
error = pthread_mutex_init(&mutex, &mattr);
errorout("pthread_mutex_init = %d\n");
error = pthread_condattr_init(&cvattr);
errorout("pthread_condattr_init = %d\n");
if (opt_shared) {
error = pthread_condattr_setpshared(&cvattr, PTHREAD_PROCESS_SHARED);
errorout("pthread_condattr_setpshared = %d\n");
}
error = pthread_cond_init(&cond, &cvattr);
errorout("pthread_cond_init = %d\n");
td = (pthread_t*)malloc(sizeof(pthread_t) * opt_threads);
if (td==NULL) {
perror("malloc");
goto out;
}
for (i=0;i<opt_threads;i++) {
error = pthread_create( &(td[i]), NULL, thread_main, NULL);
errorout("pthread_create()=%d\n");
}
fprintf(stderr,"waiting 1 second after all pthread_create() calls\n");
sleep(1);
for (i=0;i<opt_threads;i++) {
error = pthread_mutex_lock(&mutex);
errorout("pthread_mutex_lock()=%d\n");
value++;
error = pthread_cond_signal(&cond);
errorout("pthread_cond_signal()=%d\n");
fprintf(stderr,"post pthread_cond_signal() value=%d\n", value);
error = pthread_mutex_unlock(&mutex);
errorout("pthread_mutex_unlock()=%d\n");
if (opt_wait) {
fprintf(stderr,"wait...\n");
sleep(1);
}
}
fprintf(stderr,"waiting for thread end\n");
for (i=0;i<opt_threads;i++) {
error = pthread_join(td[i],NULL);
errorout("pthread_join()=%d\n");
}
fprintf(stderr,"all threads ended\n");
free(td);
out:
return error;
}