severe problems with NGPT 2.0.4
"Dr. Uwe Girlich" <[email protected]>
| Newsgroups | gmane.linux.ngpt.devel |
|---|---|
| Message-ID | <[email protected]> |
Hello! I just found out, that a new NGPT 2.0.4 library is available. Good! 4 out of my 8 private patch files are gone. Even better. But my test program (attached) does not work anymore. I may have posted this simple consumer&producer example already but the fact is now, that it works with 2.0.3 but not with 2.0.4. I simply set LD_LIBRARY_PATH to the old (2.0.3) lib directory and all was well. I started simply ./pc which acts as the consumer. It forks 1 producer and establishes a simply queue. The consumer prints out all received charactes, so a working program should print lots and lots (without end, you have to press Ctrl-C) of characters on the screen. All producers (default 1) fill the queue with random characters. The queue itself is locked with a mutex, both sides wake the other side up, if it is needed (consumer->producers, when queue is empty, producers->consumer, when queue is full). pthread_cond_signal() (-s1) is a bit better than pthread_cond_broadcast() (-s0, default) but in the end I often get EAGAIN as result of pthread_mutex_unlock(). Really strange! The test was made on a 2 processor machine (PIII 1GHz) with SuSE Linux 8.1 on the SuSE Linux kernel 2.4.19, which contains (after some requests by me) the current futex patch. The ngpt test program test_str03 works. 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
pc.c
(text/plain, 6.6 KB)
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef BSIZE
#define BSIZE 10
#endif
typedef struct {
char buf[BSIZE];
int occupied;
int nextin;
int nextout;
pthread_mutex_t mutex;
pthread_cond_t more;
pthread_cond_t less;
} buffer_t;
void producer_driver(buffer_t *b);
void consumer_driver(buffer_t *b);
int opt_use_signal = 0;
int opt_use_keys = 0;
int opt_num_producer = 1;
#define error_check(x) if (error != 0) { \
int myerrno = errno; \
fprintf(stderr,"pid %d file %s line %d\n%s()=%d, errno=%d, %s\n", \
getpid(), __FILE__, __LINE__, \
x, error, myerrno, strerror(myerrno)); \
abort(); \
}
void
usage(char *progname)
{
fprintf(stderr,"%s: Producer+Consumer example\n", progname);
fprintf(stderr,"-s<num>\tuse signal (num!=0) or broadcast (default)\n");
fprintf(stderr,"-k<num>\tuse keyboard (num!=0) or self-made input (default)\n");
fprintf(stderr,"-p<num>\tuse num producers (default 1)\n");
fprintf(stderr,"-h\tthis help\n");
exit(1);
}
int
main(int argc, char **argv) {
buffer_t *buffer;
pthread_mutexattr_t mattr;
pthread_condattr_t cvattr_less, cvattr_more;
int error;
int c;
int i;
int buffer_id;
while ((c = getopt(argc, argv, "s:k:p:h")) != -1) {
switch (c) {
case 's':
opt_use_signal = atoi(optarg);
break;
case 'k':
opt_use_keys = atoi(optarg);
break;
case 'p':
opt_num_producer = 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,"use signal: %s\n", opt_use_signal ? "yes" : "no");
fprintf(stderr,"use keys : %s\n", opt_use_keys ? "yes" : "no");
fprintf(stderr,"#producers: %d\n", opt_num_producer);
fprintf(stderr,"init...\n");
if ((buffer_id=shmget(IPC_PRIVATE, sizeof(buffer_t),
IPC_CREAT | S_IRUSR | S_IWUSR))==-1) {
perror("shmget");
exit(1);
}
if ((buffer=(buffer_t*)shmat(buffer_id,0,0)) == (buffer_t*)-1) {
perror("shmat");
exit(1);
}
if (shmctl(buffer_id,IPC_RMID,(struct shmid_ds*) 0) == -1) {
perror("shmctl (remove shm)");
exit(1);
}
buffer->occupied = buffer->nextin = buffer->nextout = 0;
/* Mutex */
fprintf(stderr,"pthread_mutexattr_init\n");
error = pthread_mutexattr_init(&mattr);
error_check("pthread_mutexattr_init");
fprintf(stderr,"pthread_mutexattr_setpshared\n");
error = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
error_check("pthread_mutexattr_setpshared");
fprintf(stderr,"pthread_mutex_init\n");
error = pthread_mutex_init(&buffer->mutex, &mattr);
error_check("pthread_mutex_init");
/* cond var 1 */
fprintf(stderr,"pthread_condattr_init(less)\n") ;
error = pthread_condattr_init(&cvattr_less);
error_check("pthread_condattr_init");
fprintf(stderr,"pthread_condattr_setpshared(less)\n");
error = pthread_condattr_setpshared(&cvattr_less, PTHREAD_PROCESS_SHARED);
error_check("pthread_condattr_setpshared");
fprintf(stderr,"pthread_cond_init(less)\n");
error = pthread_cond_init(&buffer->less, &cvattr_less);
error_check("pthread_cond_init");
/* cond var 2 */
fprintf(stderr,"pthread_condattr_init(more)\n");
error = pthread_condattr_init(&cvattr_more);
error_check("pthread_condattr_init");
fprintf(stderr,"pthread_condattr_setpshared(more)\n");
error = pthread_condattr_setpshared(&cvattr_more, PTHREAD_PROCESS_SHARED);
error_check("pthread_condattr_setpshared");
fprintf(stderr,"pthread_cond_init(more)\n");
error = pthread_cond_init(&buffer->more, &cvattr_more);
error_check("pthread_cond_init");
fprintf(stderr,"init finished\n");
/* make sure the childs don't use too much CPU yet */
error = pthread_mutex_lock(&buffer->mutex);
error_check("pthread_mutex_lock");
for (i=0;i<opt_num_producer;i++) {
pid_t pid;
pid = fork();
switch(pid) {
case 0: /* child */
producer_driver(buffer);
exit(0);
break;
case -1: /* error */
perror("could not fork()");
exit(1);
break;
default: /* parent */
/* do nothing */
break;
}
}
/* enable all the waiting childs */
error = pthread_mutex_unlock(&buffer->mutex);
error_check("pthread_mutex_unlock");
consumer_driver(buffer);
return(0);
}
void producer(buffer_t *b, char item)
{
int error = 0;
error = pthread_mutex_lock(&b->mutex);
error_check("pthread_mutex_lock");
while (b->occupied >= BSIZE) {
error = pthread_cond_wait(&b->less, &b->mutex);
error_check("pthread_cond_wait");
}
assert(b->occupied < BSIZE);
b->buf[b->nextin++] = item;
b->nextin %= BSIZE;
b->occupied++;
/* now: either b->occupied < BSIZE and b->nextin is the index
of the next empty slot in the buffer, or
b->occupied == BSIZE and b->nextin is the index of the
next (occupied) slot that will be emptied by a consumer
(such as b->nextin == b->nextout) */
if (opt_use_signal) {
error = pthread_cond_signal(&b->more);
error_check("pthread_cond_signal");
}
else {
error = pthread_cond_broadcast(&b->more);
error_check("pthread_cond_broadcast");
}
error = pthread_mutex_unlock(&b->mutex);
error_check("pthread_mutex_unlock");
}
void producer_driver(buffer_t *b)
{
int item;
fprintf(stderr,"producer: pid=%d\n", getpid());
while (1) {
if (opt_use_keys) {
item = getchar();
}
else {
item = 32 + rand() % 64;
}
producer(b, (char)item);
}
}
char consumer(buffer_t *b)
{
int error;
char item;
error = pthread_mutex_lock(&b->mutex);
error_check("pthread_mutex_lock");
while(b->occupied <= 0) {
error = pthread_cond_wait(&b->more, &b->mutex);
error_check("pthread_cond_wait");
}
assert(b->occupied > 0);
item = b->buf[b->nextout++];
b->nextout %= BSIZE;
b->occupied--;
/* now: either b->occupied > 0 and b->nextout is the index
of the next occupied slot in the buffer, or
b->occupied == 0 and b->nextout is the index of the next
(empty) slot that will be filled by a producer (such as
b->nextout == b->nextin) */
if (opt_use_signal) {
error = pthread_cond_signal(&b->less);
error_check("pthread_cond_signal");
}
else {
error = pthread_cond_broadcast(&b->less);
error_check("pthread_cond_broadcast");
}
error = pthread_mutex_unlock(&b->mutex);
error_check("pthread_mutex_unlock");
return(item);
}
void consumer_driver(buffer_t *b)
{
char item;
fprintf(stderr,"consumer: pid=%d\n", getpid());
while (1) {
if ((item = consumer(b)) == '\0')
break;
putchar(item);
fflush(stdout);
}
}