Thanks for your reply. This isn't the problem however... the
pthread_create simply segfaults and doesn't return. Multiple cpu's or
cores aren't present in my system either. Is it possible that this
doesn't work because I'm using cygwin?
> Thanks for your reply. This isn't the problem however... the
> pthread_create simply segfaults and doesn't return. Multiple cpu's or
> cores aren't present in my system either. Is it possible that this
> doesn't work because I'm using cygwin?
I assume you mean pthread_cond_timedwait segfaults. Make sure you
properly initialize the c.v. and don't create it on the stack of a
function that returns! Post the code that signals the c.v.
DS
Thanks for looking... This is the whole code... There is no timedwait
but just a wait. The code that would send a signal is never reached
however (probably because of a long sleep in that thread and it thus
segfaults before a signal is received).
Sincerely,
Stéphane
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h> // needed for pthreads
#include <unistd.h> // for usleep()
#include "prodcons.h"
static unsigned int prodCount = 0; // The number of produces items
static unsigned int bufferHead = 0; // Indicates the first free place
in buffer or undefined when prodCount = BUFFER_SIZE
static unsigned int inBufferCnt = 0; // Number of items in buffer
static pthread_mutex_t bufferLock;
static pthread_cond_t bufferNotFull;
static pthread_cond_t availForCons[NROF_CONSUMERS]; // Conditions
variables for the availability of items on the belt (per consumer)
static const unsigned short int ALL_ONES = 0xFFFF;
static int producing = 1;
static void rsleep (int t);
/* producer thread */
static void * producer (void * arg)
{
ITEM item; // a produced item
arg = arg;
while (prodCount < NROF_ITEMS) // While not all items are produced
{
rsleep (PRODUCER_SLEEP_FACTOR);
// TODO: produce new item and put it into buffer[]
item = (random() % NROF_CONSUMERS) + (prodCount << NROF_BITS_DEST);
prodCount++;
printf("m%d\n",pthread_mutex_lock(&bufferLock));
printf("justlocked\n");
if(inBufferCnt == BUFFER_SIZE)
{
printf("full buffer\n");
printf("c%d\n",pthread_cond_wait(&bufferNotFull, &bufferLock));
printf("not full anymore\n");
}
buffer[bufferHead] = item;
bufferHead = (bufferHead + 1) % BUFFER_SIZE;
inBufferCnt++;
if(inBufferCnt == 1)
{
printf("consumer signaled\n");
pthread_cond_signal(&availForCons[buffer[bufferHead - 1] & ~
(ALL_ONES << NROF_BITS_DEST)]);
}
printf("%04x\n", item); // write info to stdout, putting it inside
the CS ensures no two threads write to stdout at the same time
printf("unlockingnext\n");
pthread_mutex_unlock(&bufferLock);
}
producing = 0;
return NULL;
}
/* consumer thread */
void * consumer (void * arg)
{
ITEM item; // a consumed item
int id; // identifier of this consumer (value
0..NROF_CONSUMERS-1)
// Set the id
id = *(int*)arg;
printf("%d",id);
while (producing || inBufferCnt > 0)
{
rsleep (100 * NROF_CONSUMERS);
printf("cLock\n\n\n\n");
if(inBufferCnt == 0 || (buffer[bufferHead - 1] & ~(ALL_ONES <<
NROF_BITS_DEST)) != id) // inBufferCnt == 0 or the item might be for
another consumer (caused by a previous iteration)
{
printf("c%d\n",pthread_cond_wait(&availForCons[id],
&bufferLock));
}
item = buffer[bufferHead - 1];
bufferHead = (bufferHead + BUFFER_SIZE - 1) % BUFFER_SIZE;
inBufferCnt--;
if(inBufferCnt == BUFFER_SIZE - 1)
{
pthread_cond_signal(&bufferNotFull);
}
else if(inBufferCnt > 0 && (buffer[bufferHead - 1] & ~(ALL_ONES <<
NROF_BITS_DEST)) != id)
{
pthread_cond_signal(&availForCons[buffer[bufferHead - 1] & ~
(ALL_ONES << NROF_BITS_DEST)]);
}
printf("%*s C%d:%04x\n", 7*id, "", id, item); // write info
to stdout (with indentation)
printf("cUnlock\n");
pthread_mutex_unlock(&bufferLock);
}
return NULL;
}
int main (/*int argc, char * argv[]*/)
{
int consumerCount = 0;
int consumerIter;
int exitcode = 0;
pthread_t producerTh;
pthread_t consumerTh[NROF_CONSUMERS];
// Initializations
srandom (time(NULL));
pthread_mutex_init(&bufferLock, NULL);
pthread_cond_init(&bufferNotFull, NULL);
for(consumerIter = 0; consumerIter < NROF_CONSUMERS; consumerIter++)
{
pthread_cond_init(&availForCons[consumerIter], NULL);
}
// Create a producer-thread and NROF_CONSUMERS consumer-threads
while(consumerCount < NROF_CONSUMERS && !pthread_create(&consumerTh
[consumerCount], NULL, consumer, (void *)consumerCount))
{
consumerCount++;
}
if(consumerCount != NROF_CONSUMERS || pthread_create(&producerTh,
NULL, producer, NULL))
{
printf("Some thread could not be created. There might have been
insufficient resources available. Now quitting...");
exitcode = -1;
}
// Wait until all threads are finished
for(consumerIter = 0; consumerIter < consumerCount; consumerIter++)
{
pthread_join(consumerTh[consumerIter], NULL);
}
pthread_join(producerTh, NULL);
// Close everything
pthread_mutex_destroy(&bufferLock);
pthread_cond_destroy(&bufferNotFull);
for(consumerIter = 0; consumerIter < NROF_CONSUMERS; consumerIter++)
{
pthread_cond_destroy(&availForCons[consumerIter]);
}
return (exitcode);
}
/*
* rsleep(int t)
*
* The calling thread will be suspended for a random amount of time
between 0 and t microseconds
*/
static void rsleep (int t)
{
usleep (random () % t);
}
>
> /* consumer thread */
> void * consumer (void * arg)
> {
> ITEM item; // a consumed item
> int id; // identifier of this consumer (value
> 0..NROF_CONSUMERS-1)
>
> // Set the id
> id = *(int*)arg;
> printf("%d",id);
> while (producing || inBufferCnt > 0)
> {
> rsleep (100 * NROF_CONSUMERS);
>
> printf("cLock\n\n\n\n");
> if(inBufferCnt == 0 || (buffer[bufferHead - 1] & ~(ALL_ONES <<
> NROF_BITS_DEST)) != id) // inBufferCnt == 0 or the item might be for
> another consumer (caused by a previous iteration)
> {
> printf("c%d\n",pthread_cond_wait(&availForCons[id],
> &bufferLock));
Boom. Here you call 'pthread_cond_wait', but don't hold the mutex. You
also access 'bufferHead' and many other shared variables without
holding the mutex that protects them.
DS
Wow, I hadn't noticed that... changed it like seen below, but still no
success... the same failure... I have posted the output as well...
regards,
Stéphane
/* consumer thread */
void * consumer (void * arg)
{
ITEM item; // a consumed item
int id; // identifier of this consumer (value
0..NROF_CONSUMERS-1)
// Set the id
id = *(int*)arg;
printf("%d",id);
while (prodCount < NROF_ITEMS || inBufferCnt > 0)
{
rsleep (100 * NROF_CONSUMERS);
pthread_mutex_lock(&bufferLock);
printf("cLock\n");
if(inBufferCnt == 0 || (buffer[bufferHead - 1] & ~(ALL_ONES <<
NROF_BITS_DEST)) != id) // inBufferCnt == 0 or the item might be for
another consumer (caused by a previous iteration)
{
printf("c%d\n",pthread_cond_wait(&availForCons[id],
&bufferLock));
}
item = buffer[bufferHead - 1];
bufferHead = (bufferHead + BUFFER_SIZE - 1) % BUFFER_SIZE;
inBufferCnt--;
if(inBufferCnt == BUFFER_SIZE - 1)
{
pthread_cond_signal(&bufferNotFull);
}
else if(inBufferCnt > 0 && (buffer[bufferHead - 1] & ~(ALL_ONES <<
NROF_BITS_DEST)) != id)
{
pthread_cond_signal(&availForCons[buffer[bufferHead - 1] & ~
(ALL_ONES << NROF_BITS_DEST)]);
}
printf("%*s C%d:%04x\n", 7*id, "", id, item); // write info
to stdout (with indentation)
printf("cUnlock\n");
pthread_mutex_unlock(&bufferLock);
}
return NULL;
}
//Output:
m0
justlocked
consumer signaled
0002
unlockingnext
m0
justlocked
0102
unlockingnext
m0
justlocked
0201
unlockingnext
m0
justlocked
0300
unlockingnext
m0
justlocked
0400
unlockingnext
m0
justlocked
0501
unlockingnext
m0
justlocked
0602
unlockingnext
m0
justlocked
0702
unlockingnext
m0
justlocked
0800
unlockingnext
m0
justlocked
0901
unlockingnext
m0
justlocked
full buffer
804755 [unknown (0x3C4)] prodcons 2620 _cygtls::handle_exceptions:
Error while
dumping state (probably corrupted stack)
Segmentation fault (core dumped)
> full buffer
> 804755 [unknown (0x3C4)] prodcons 2620 _cygtls::handle_exceptions:
> Error while
> dumping state (probably corrupted stack)
> Segmentation fault (core dumped)
Looks like you're corrupting the stack. How is 'buffer' allocated? Are
you sure you aren't accessing it out of bounds?
DS
Yup, you're right I was accessing that out of bounds too! I really
ought to watch out for those things, sorry for bothering you for these
stupid mistakes. Of course I ran into a lot of other problems again
after that :P, but I'll stop now... I think I can handle them.
Thanks!
Sincerely,
Stéphane
[...]
FWIW, you can do a very simple bounded circular buffer like:
// pseudo-code typed in news reader.
___________________________________________________________________
#define DEPTH 8192
struct foo
{
char blah[128];
};
struct data
{
int in_use;
struct foo foo;
};
struct cbuf
{
struct data buffer[DEPTH]; /* = { { 0 } } */
size_t head; /* = 0 */
size_t tail; /* = 0 */
pthread_mutex_t mutex;
pthread_cond_t cond;
};
void
cbuf_push(struct cbuf* self,
struct foo const* f)
{
size_t i;
pthread_mutex_lock(&self->mutex);
i = (self->head++) % DEPTH;
while (self->buffer[i].in_use)
{
pthread_cond_wait(&self->cond, &self->mutex);
}
self->buffer[i].foo = *f;
self->buffer[i].in_use = 1;
pthread_mutex_unlock(&self->mutex);
pthread_cond_broadcast(&self->cond);
}
void
cbuf_pop(struct cbuf* self,
struct foo* f)
{
size_t i;
pthread_mutex_lock(&self->mutex);
i = (self->tail++) % DEPTH;
while (! self->buffer[i].in_use)
{
pthread_cond_wait(&self->cond, &self->mutex);
}
*f = self->buffer[i].foo;
self->buffer[i].in_use = 0;
pthread_mutex_unlock(&self->mutex);
pthread_cond_broadcast(&self->cond);
}
___________________________________________________________________
There ya go.