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;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.