C pthread join/exit Threads (Exit wont work) - c

im trying to learn Threads, but i have a issue..
I'am trying to create multiple Threads as defined by ThreadCount and close them all after the work is done.
#define ThreadCount 5
just a short snippet of my main
pthread_t pro;
pthread_t con[ThreadCount];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&pro, &attr, producer, fifo);
for(unsigned int i = 0; i <ThreadCount;++i){
pthread_create (&con[i], NULL, consumer, createhilfsStruct(i,fifo));
}
for(unsigned int i = 0; i <ThreadCount;++i){
pthread_join (con[i], NULL);
}
pthread_join (pro, NULL);
printf("Done");
pthread_exit(NULL);
__
typedef struct{
int threadName;
queue* queue;
}hilfsStruct;
typedef struct {
job* buf[QUEUESIZE];
long head, tail;
int full, empty, currentPages, done;
pthread_mutex_t *mut;
pthread_cond_t *notFull, *notEmpty;
} queue;
hilfsStruct* createhilfsStruct(int threadName, queue* q){
hilfsStruct* h = (hilfsStruct*)malloc (sizeof (hilfsStruct));
h->queue = q;
h->threadName = threadName;
return h;
}
queue *queueInit (void) {
queue *q;
q = (queue *)malloc (sizeof (queue));
if (!q) return (NULL);
q->empty = 1;
q->full = 0;
q->head = 0;
q->tail = 0;
q->currentPages = 0;
q->done = 0;
q->mut = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t));
pthread_mutex_init (q->mut, NULL);
q->notFull = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
pthread_cond_init (q->notFull, NULL);
q->notEmpty = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
pthread_cond_init (q->notEmpty, NULL);
return (q);
}
And in my consumer function i have a query to check if fifo->done is true and if its true i use exit(0); to kill the program ==> printf("Done") in the main cant get called [obviously]
If i swap the exit(0) for an pthread_exit(3); // i found this online but i cant figure out why 3
It doesn't exit the thread and the program is just idling and never closes / never reaches anything below the pthread_join
My first try was to use pthread_t con, pro; instead of pthread_t con[..] and just pthread_join(con,NULL) but that wasn't working either.
What am i doing wrong?
Ty guys, and have a nice day

Related

Reduce overhead in mutex

I am learning mutex currently and the following is the test code. It works perfectly fine. It creates another instance after one is done. Yet, it also introduces overhead according to here.
How efficient is locking an unlocked mutex? What is the cost of a mutex?. How can I modify my code to improve the efficiency?
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
typedef struct _context_t {
uint64_t id;
char *name;
bool initialized;
} context_t;
context_t *ctx = NULL;
context_t *get_instance() {
pthread_mutex_lock(&lock);
if (ctx == NULL) {
ctx = (context_t *)malloc(sizeof(context_t));
assert(ctx != NULL);
ctx->initialized = false;
}
pthread_mutex_unlock(&lock);
return ctx;
}
int id = 0;
void *do_work(void *arg) {
context_t *ctx = get_instance();
if (!ctx->initialized) {
ctx->name = (char *)arg;
ctx->id = ++id;
ctx->initialized = true;
}
printf("name=%s\tid=%ld\n", ctx->name, ctx->id);
return NULL;
}
int main() {
int rc;
pthread_t p1, p2;
rc = pthread_create(&p1, NULL, do_work, "A");
assert(rc == 0);
rc = pthread_create(&p2, NULL, do_work, "B");
assert(rc == 0);
rc = pthread_join(p1, NULL);
assert(rc == 0);
rc = pthread_join(p2, NULL);
assert(rc == 0);
if (ctx) {
free(ctx);
}
return 0;
}
Instead of having two threads racing to create the context_t, you should create it once before the threads start, and pass its address to the threads explicitly.
Note that you can pass multiple arguments via pthread_create() by putting them in a struct and passing its address.
Then you won't need a mutex at all, because the threads will only read from ctx rather than potentially writing to it.

why doesn't sem_wait block

static int res1 = 0;
static int res2 = 0;
static int res3 = 0;
static int counter = 0;
static sem_t sem;
void * func_thread1(void *p)
{
sleep(2);
res1 = 1;
printf("func_thread1\n");
sem_post(&sem);
return NULL;
}
void * func_thread2(void *p)
{
sleep(2);
res2 = 2;
printf("func_thread2\n");
sem_post(&sem);
return NULL;
}
void * func_thread3(void *p)
{
sem_wait(&sem);
sem_wait(&sem);
res3 = res1 + res2;
printf("func_thread3\n");
return NULL;
}
void main()
{
sem_init(&sem, 0, counter);
pthread_t pd1, pd2, pd3;
pthread_create(&pd1, NULL, func_thread1, NULL);
pthread_create(&pd2, NULL, func_thread2, NULL);
pthread_create(&pd3, NULL, func_thread3, NULL);
//pthread_join(pd3, NULL);
printf("main_thread\n");
printf("%d", res3);
}
I'm trying to understand how semaphore works.
I'm trying to make the td3 block to wait for the td1 and the td2.
In my opinion, the sem_wait will block twice. If the sem_posts in func_thread1 and in func_thread2 are executed, func_thread3 could continue.
However, it doesn't work unless I add pthread_join(td3, NULL) in main. I think the join is not necessary because sem_wait can block.
So pthread_join is necessary or I use semaphore incorrectly?
pthread_join is mandatory in your implementation.
Otherwise your process finishes (ie. main returns), and all tasks (ie. threads) are killed before thread 3 prints anything.

Pthread runtime errors

I'm having trouble debugging the following program I wrote. The idea is to have two seperate threads; one thread executes a 5 second countdown while the other waits for key input from the user. Whichever thread completes first should cancel the sibling thread and exit the program. However, the following code just hangs.
Any help would be appreciated, but I would be most grateful for an explanation as to the problem.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // For sleep()
#define NUM_THREADS 2
// The stuct to be passed as an argument to the countdown routine
typedef struct countdown_struct {
pthread_t *thread;
signed int num_secs;
} CountdownStruct;
// Struct for passing to the input wait routine
typedef struct wait_struct {
pthread_t *thread;
int *key;
} WaitStruct;
// Countdown routine; simply acts as a timer counting down
void * countdown(void *args)
{
CountdownStruct *cd_str = (CountdownStruct *)args;
signed int secs = cd_str->num_secs;
printf("Will use default setting in %d seconds...", secs);
while (secs >= 0)
{
sleep(1);
secs -= 1;
printf("Will use default setting in %d seconds...", secs);
}
// Cancel the other struct
pthread_cancel(*(cd_str->thread));
return NULL;
}
// Waits for the user to pass input through the tty
void * wait_for_input(void *args)
{
WaitStruct *wait_str = (WaitStruct *) args;
int c = 0;
do {
c = getchar();
} while (!(c == '1' || c == '2'));
*(wait_str->key) = c;
// Cancel the other thread
pthread_cancel(*(wait_str->thread));
return NULL;
}
int main(int argc, char **argv)
{
pthread_t wait_thread;
pthread_t countdown_thread;
pthread_attr_t attr;
int key=0;
long numMillis=5000;
int rc=0;
int status=0;
// Create the structs to be passe as paramaters to both routines
CountdownStruct *cd_str = (CountdownStruct *) malloc(sizeof(CountdownStruct));
if (cd_str == NULL)
{
printf("Couldn't create the countdown struct. Aborting...");
return -1;
}
cd_str->thread = &wait_thread;
cd_str->num_secs = 5;
WaitStruct *wait_str = (WaitStruct *) malloc(sizeof(WaitStruct));
if (wait_str == NULL)
{
printf("Couldn't create the iput wait struct. Aborting...");
return -1;
}
wait_str->thread = &countdown_thread;
wait_str->key = &key;
// Create the joinable attribute
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// Create both threads
rc = pthread_create(&countdown_thread, &attr, countdown, (void *) cd_str);
if (rc) { printf("Error with the thread creation!"); exit(-1); }
rc = pthread_create(&wait_thread, &attr, wait_for_input, (void *) wait_str);
if (rc) { printf("Error with the thread creation!"); exit(-1); }
// Destroy the pthread_attribute
pthread_attr_destroy(&attr);
// now join on the threads and wait for main
pthread_join(wait_thread, NULL);
pthread_join(countdown_thread, NULL);
// Call pthread_exit
pthread_exit(NULL);
// Free the function structs
free(cd_str);
free(wait_str);
}
Getchar is not required to be a cancellation point. Select and pselect are. Even if you want to continue to use a countdown thread you could still provide a cancellation point in the opposing thread by use of select.
I had reasonable behavior with the following modified wait_for_input()
// Waits for the user to pass input through the tty
void * wait_for_input(void *args)
{
WaitStruct *wait_str = (WaitStruct *) args;
int c = 0;
fd_set readFds;
int numFds=0;
FD_ZERO(&readFds);
do {
struct timeval timeout={.tv_sec=8,.tv_usec=0};
/* select here is primarily to serve as a cancellation
* point. Though there is a possible race condition
* still between getchar() getting called right as the
* the timeout thread calls cancel.().
* Using the timeout option on select would at least
* cover that, but not done here while testing.
*******************************************************/
FD_ZERO(&readFds);
FD_SET(STDOUT_FILENO,&readFds);
numFds=select(STDOUT_FILENO+1,&readFds,NULL,NULL,&timeout);
if(numFds==0 )
{
/* must be timeout if no FD's selected */
break;
}
if(FD_ISSET(STDOUT_FILENO,&readFds))
{
printf("Only get here if key pressed\n");
c = getchar();
}
} while (!(c == '1' || c == '2'));
*(wait_str->key) = c;
// Cancel the other thread
pthread_cancel(*(wait_str->thread));
return NULL;
}

Producer-consumer example. Sometimes the execution deadlocks

I am trying to learn how to use pthreads following Douglas Niehaus' classes.
Now I'm in the middle of the producer-consumer problem. This is the solution I've reached so far:
PRODUCER:
void *producer (void *parg) {
queue *fifo;
int item_produced;
pcdata *mydata;
int my_tid;
int *total_produced;
mydata = (pcdata *) parg;
fifo = mydata->q;
total_produced = mydata->count;
my_tid = mydata->tid;
/*
* Continue producing until the total produced reaches the
* configured maximum
*/
while (1) {
/*
* Do work to produce an item. Tthe get a slot in the queue for
* it. Finally, at the end of the loop, outside the critical
* section, announce that we produced it.
*/
do_work(PRODUCER_CPU, PRODUCER_BLOCK);
pthread_mutex_lock(fifo->mutex);
/*
* If the queue is full, we have no place to put anything we
* produce, so wait until it is not full.
*/
while(fifo->full && *total_produced != WORK_MAX) {
pthread_cond_wait(fifo->notFull,fifo->mutex);
}
if(*total_produced >= WORK_MAX) {
printf("PRODUCER %d is exitting because the production reached the MAX\n",my_tid);
pthread_cond_signal(fifo->notFull);
pthread_mutex_unlock(fifo->mutex);
break;
}
/*
* OK, so we produce an item. Increment the counter of total
* widgets produced, and add the new widget ID, its number, to the
* queue.
*/
item_produced = (*total_produced)++;
queueAdd (fifo, item_produced);
pthread_cond_signal(fifo->notEmpty);
pthread_mutex_unlock(fifo->mutex);
/*
* Announce the production outside the critical section
*/
printf("prod %d:\t %d.\n", my_tid, item_produced);
}
printf("prod %d:\texited\n", my_tid);
return (NULL);
}
CONSUMER:
void *consumer (void *carg)
{
queue *fifo;
int item_consumed;
pcdata *mydata;
int my_tid;
int *total_consumed;
mydata = (pcdata *) carg;
fifo = mydata->q;
total_consumed = mydata->count;
my_tid = mydata->tid;
/*
* Continue producing until the total consumed by all consumers
* reaches the configured maximum
*/
while (1) {
/*
* If the queue is empty, there is nothing to do, so wait until it
* si not empty.
*/
pthread_mutex_lock(fifo->mutex);
while(fifo->empty && *total_consumed != WORK_MAX) {
pthread_cond_wait(fifo->notEmpty,fifo->mutex);
}
if(*total_consumed >= WORK_MAX) {
printf("CONSUMER %d is exitting because the compsuption reached the MAX\n",my_tid);
pthread_cond_signal(fifo->notEmpty);
pthread_mutex_unlock(fifo->mutex);
break;
}
/*
* Remove the next item from the queue. Increment the count of the
* total consumed. Note that item_consumed is a local copy so this
* thread can retain a memory of which item it consumed even if
* others are busy consuming them.
*/
queueRemove (fifo, &item_consumed);
(*total_consumed)++;
pthread_cond_signal(fifo->notFull);
pthread_mutex_unlock(fifo->mutex);
/*
* Do work outside the critical region to consume the item
* obtained from the queue and then announce its consumption.
*/
do_work(CONSUMER_CPU,CONSUMER_CPU);
printf ("con %d:\t %d.\n", my_tid, item_consumed);
}
printf("con %d:\texited\n", my_tid);
return (NULL);
}
This seems to work fine with rather small number of producers and consumers, for example 100 consumers and 50 producers or viceversa. But if I try the code with more than 2000 producers and/or consumers, the execution hangs. I think I've reached a deadlock but I'm unable to find it.
Any help would be appreciated.
NOTE:
The signals inside the if-block:
if(*total_consumed >= WORK_MAX) { ... }
and the if-block:
if(*total_consumed >= WORK_MAX) {...}
are something that I added because the execution without them would hang up with more than 5 producers and/or consumers.
My reasoning is that if the work limit has been reached, the other producers should be told so they can exit too. And the same goes for the consumers.
NOTE 2:
The following code is already provided to the student:
typedef struct {
int buf[QUEUESIZE]; /* Array for Queue contents, managed as circular queue */
int head; /* Index of the queue head */
int tail; /* Index of the queue tail, the next empty slot */
int full; /* Flag set when queue is full */
int empty; /* Flag set when queue is empty */
pthread_mutex_t *mutex; /* Mutex protecting this Queue's data */
pthread_cond_t *notFull; /* Used by producers to await room to produce*/
pthread_cond_t *notEmpty; /* Used by consumers to await something to consume*/
} queue;
typedef struct {
queue *q;
int *count;
int tid;
} pcdata;
/******************************************************/
queue *queueInit (void) {
queue *q;
/*
* Allocate the structure that holds all queue information
*/
q = (queue *)malloc (sizeof (queue));
if (q == NULL) return (NULL);
/*
* Initialize the state variables. See the definition of the Queue
* structure for the definition of each.
*/
q->empty = 1;
q->full = 0;
q->head = 0;
q->tail = 0;
/*
* Allocate and initialize the queue mutex
*/
q->mutex = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t));
pthread_mutex_init (q->mutex, NULL);
/*
* Allocate and initialize the notFull and notEmpty condition
* variables
*/
q->notFull = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
pthread_cond_init (q->notFull, NULL);
q->notEmpty = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
pthread_cond_init (q->notEmpty, NULL);
return (q);
}
And in main:
int main (int argc, char *argv[]) {
// More initializations
pthread_t *con;
int cons;
int *concount;
queue *fifo;
int i;
pthread_t *pro;
int *procount;
int pros;
pcdata *thread_args;
fifo = queueInit ();
if (fifo == NULL) {
fprintf (stderr, "main: Queue Init failed.\n");
exit (1);
}
// More initializations and creation of the threads:
for (i=0; i<pros; i++){
/*
* Allocate memory for each producer's arguments
*/
thread_args = (pcdata *)malloc (sizeof (pcdata));
if (thread_args == NULL) {
fprintf (stderr, "main: Thread_Args Init failed.\n");
exit (1);
}
/*
* Fill them in and then create the producer thread
*/
thread_args->q = fifo;
thread_args->count = procount;
thread_args->tid = i;
pthread_create (&pro[i], NULL, producer, thread_args);
}
}
}

c, pthread_create gives segmentation fault ?

I'm keep getting a segmentation fault from where I create thread and declare some variables in the struct...
Does anyone know why?
dispatch_queue_t *dispatch_queue_create(queue_type_t queueType){
int cores = num_cores();
printf("message-queuecreate1");
dispatch_queue_t *dispatch_queue = (dispatch_queue_t *) malloc(sizeof(dispatch_queue_t));
dispatch_queue->HEAD = NULL;
dispatch_queue->END = NULL;
//create a thread array for dispatcher and worker threads
dispatch_queue_thread_t *threads[cores+1];
threads[cores+1]= (dispatch_queue_thread_t *)malloc(sizeof(dispatch_queue_thread_t));
//create semaphores
sem_t queue_task_semaphore;
sem_t queue_thread_semaphore;
sem_t queue_wait_semaphore;
sem_init(&queue_task_semaphore, 0, 1);
sem_init(&queue_thread_semaphore,0,1);
sem_init(&queue_wait_semaphore,0,1);
dispatch_queue->queue_task_semaphore = queue_task_semaphore;
dispatch_queue->queue_thread_semaphore = queue_thread_semaphore;
dispatch_queue->queue_wait_semaphore = queue_wait_semaphore;
//create dispatcher thread
//segmentation fault #1////////////////
threads[0]->current_task=NULL;
threads[0]->queue=dispatch_queue;
pthread_create(threads[0]->thread, NULL, dispatcher_threadloop, threads[0]);
//////////////////////////////////////
if (queueType == CONCURRENT){
int i = 0;
int thread_id=0;
//create worker thread array if the type of the queue is concurrent
while(i<cores){
//create worker thread
thread_id = i+1;
//segmentation fault #2//////////
threads[i+1]->queue=dispatch_queue;
threads[thread_id]->thread=NULL;
threads[thread_id]->current_task=NULL;
pthread_create(threads[thread_id]->thread, NULL, worker_threadloop, (void *)(long)i);
////////////////////////////////
printf("thread %d is created\n",i);
i++;
}
} else {//do smth}
//segmentation fault# 3////////////////
threads[1]->thread=worker_thread;
threads[1]->queue=dispatch_queue;
threads[1]->current_task=NULL;
//////////////////////////////////////
}
return dispatch_queue;
}
Your code is riddled with problems:
Accessing threads[core + 1] is invalid. Also, you're not allocating memory for the threads[0] ... threads[core].
dispatch_queue_thread_t *threads[cores+1];
threads[cores+1]= ....;
So these will fail:
threads[0]->current_task=NULL; /* See above. */
threads[i+1]->queue=dispatch_queue; /* Again, no memory allocated. */
There could be other problems but I would start by slashing the cores+1 stuff and replacing it with:
for (i = 0; i < cores; i++) {
threads[i] = malloc(sizeof(*threads[i]));
}
Assuming
threads[]->thread
is a pthread_t (and not a pthread_t *)
You need to give the reference:
pthread_create(&threads[thread_id]->thread, NULL, worker_threadloop, (void *)(long)i);
.

Resources