This issue is definitely the source of a stupid mistake, but for the life of me I cannot get to the bottom of it.
I'm writing a much larger program, but I've narrowed down a constant segfault error that is coming up whenever I call pthread_join. I've included the relevant code below, hopefully someone can help me figure out what I'm doing wrong. Cheers :)
Functions for managing pthreads
void *scalloc(size_t nmemb, size_t size)
{
void *p;
p = calloc(nmemb, size);
if (p == NULL)
sys_error("Error allocating memory block (calloc).", 1);
return p;
}
pthread_t *new_thread_array(int n)
{
return scalloc(n, sizeof(pthread_t));
}
int spthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
{
int ret;
if ((ret = pthread_create(&thread, attr, start_routine, arg)) != 0)
sys_error("Error at pthread_create.", ret);
return 0;
}
int spthread_join(pthread_t thread, void **retval)
{
int ret;
if ((ret = pthread_join(thread, retval)) != 0)
sys_error("Error at pthread_join.", ret);
return 0;
}
int create_threads(pthread_t *thread_arr, int n, const pthread_attr_t *attr,
void *(*start_routine) (void *), void **arg_arr)
{
for (int i = 0; i < n; i++) {
spthread_create(&thread_arr[i], attr, start_routine, arg_arr[i]);
debug("created thread %d", i);
}
return 0;
}
int join_threads(pthread_t *thread_arr, int n, void **ret_arr)
{
debug("Starting join");
for (int i = 0; i < n; i++) {
if (ret_arr != NULL)
spthread_join(thread_arr[i], ret_arr[i]);
else {
debug("Attempting to join %d", i);
spthread_join(thread_arr[i], NULL);
debug("Joined %d", i);
}
}
return 0;
}
Test code that produces the error
void *threadfunc(void *id)
{
fflush(stdout);
fprintf(stdout, "Thread %d printing.\n", *(int *)id);
fflush(stdout);
return;
}
int threadtest(int nodes)
{
int ret;
int *targs = scalloc(nodes, sizeof(int));
int *pass[nodes];
for (int i = 0; i < nodes; i++) {
targs[i] = i;
pass[i] = &targs[i];
}
printf("Starting L1 thread test...\n");
pthread_t *threads = new_thread_array(nodes);
debug("Allocated pthread array for %i threads.", nodes);
create_threads(threads, nodes, NULL, &threadfunc, pass);
join_threads(threads, nodes, NULL);
debug("Successfully joined %i threads.", nodes);
free(targs);
free(threads);
return 0;
}
int main()
{
return threadtest(5);
}
Finally, here is the output of running the function threadtest, confirming that the segfault (appears) to occur in the parent thread, at the call to pthread_join.
Starting L1 thread test...
Allocated pthread array for 5 threads.
created thread 0
created thread 1
Thread 0 printing.
created thread 2
Thread 1 printing.
Thread 2 printing.
created thread 3
Thread 3 printing.
created thread 4
Thread 4 printing.
Starting join
Attempting to join 0
zsh: segmentation fault ./tests/L1tests
Related
I'm trying to implement a variation of the readers and writers problem in C, the variation is that writers can either be incrementers or decrementers and they should keep a running count. Below is the code I am trying to implement, I am getting the error "Segmentation Fault (core dumped). I have attempted to debug and received this feedback from gdb - #0 0x0000000000400d84 in main ().
I'd appreciate it if someone were able to explain this to me/give me tips on how to fix this fault.
Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define WAIT 20
#define NEW 0
#define DECREMENT 0
#define INCREMENT 1
#define TIME 5
#define VALUE 1
#define COMMON 0
int readerCount = NEW;
int total = 0;
int v;
sem_t mutex;
sem_t access_data;
int increment_or_decrement() {
int d;
return d = rand() % 2;
}
void *writer(void *arg) {
int version = increment_or_decrement();
int *iID = (int *) arg;
int *dID = (int *) arg;
sleep(rand() % WAIT);
sem_wait(&access_data);
if (version == INCREMENT) {
fprintf(stderr, "Incrementer %d accessed the data\n", *iID);
total++;
fprintf(stderr, "Total: %d\n", total);
}
else {
fprintf(stderr, "Decrementer %d accessed the data\n", *dID);
total--;
fprintf(stderr, "Total: %d\n", total);
}
sleep(TIME);
sem_post(&access_data);
pthread_exit(NULL);
}
void *reader(void *arg) {
int *id = (int *) arg;
sleep(rand() % WAIT);
while(1) {
if (readerCount == NEW) {
sem_wait(&mutex);
v = version;
readerCount++;
if (readerCount == 1)
sem_wait(&access_data);
sem_post(&mutex);
fprintf(stderr, "Reader %d accessed the data\n", *id);
sem_wait(&mutex);
readerCount--;
if(readerCount == NEW)
sem_post(&access_data);
sem_post(&mutex);
pthread_exit(NULL);
}
}
}
int main() {
int numReaders = rand();
int numWriters = rand();
int i;
sem_init(&mutex, COMMON, VALUE);
sem_init(&access_data, COMMON, VALUE);
pthread_t readers[numReaders];
pthread_t writers[numWriters];
int readerID[numReaders];
int writerID[numWriters];
for (i = 0; i < numReaders; i++)
readerID[i] = i;
for (i = 0; i < numWriters; i++)
writerID[i] = i;
for (i = 0; i < numReaders; i++) {
if(pthread_create(&readers[i], NULL, reader, (void *) &readerID[i]) != 0) {
printf("Child failed\n");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < numWriters; i++) {
if (pthread_create(&writers[i], NULL, writer, (void *) &writerID[i]) != 0) {
printf("Child failed\n");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < numReaders; i++) {
if (pthread_join(readers[i], NULL) != 0) {
printf("Join failed\n");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < numWriters; i++) {
if (pthread_join(writers[i], NULL) != 0) {
printf("Join failed\n");
exit(EXIT_FAILURE);
}
}
sem_destroy(&access_data);
sem_destroy(&mutex);
}
You are likely to run out of stack space if rand returns big number as indicated in comments by #WhozCraig
If you just assign some finite values instead of using rand here:
int numReaders = rand();
int numWriters = rand();
I see it running without segmentation fault
Suspect: pthread_join(readers[i], NULL)
The second argument to pthread_join should be a valid address of a var to contain address of the return value from the exiting child threads. In this case, when a child thread exits, the pthread_exit tries to write NULL at NULL, and i think that is causing seg fault. Try changing NULL to some valid address in pthread_join for both readers and writes and see if it works.
EDIT: it turns out that POSIX allows passing NULL to pthread_join (see comments below), so suspect is acquitted.
Hi I am bit new to C programming. Facing problem with producer consumer problem. When ever I try running the below code i get segmentation fault (core dumped). Please suggest where I am going wrong. But this code works for one consumer but for multiple consumer it is throwing error.
Code:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#define MAXNITEMS 20
#define MAXNTHREADS 5
void *produce(void *arg);
void *consume(void *arg);
/* globals shared by threads */
int nitems=MAXNITEMS; /* read-only by producer and consumer */
int buff[MAXNITEMS];
int Nsignals;
struct {
pthread_mutex_t mutex;
int buff[MAXNITEMS];
int nput; /* next index to store */
int nval; /* next value to store */
} put = { PTHREAD_MUTEX_INITIALIZER };
/** struct put is used by producer only ***/
struct{
pthread_mutex_t mutex;
pthread_cond_t cond;
int nready; /* number ready for consumer */
} nready = {PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER,0};
int main(int argc, char **argv)
{
int i, prod, con;
pthread_t tid_produce[MAXNTHREADS], tid_consume[MAXNTHREADS];
printf("Enter the number of producers : \n");
scanf("%d",&prod);
printf("Enter the number of consumers: \n");
scanf("%d",&con);
/* create all producers and consumers */
for (i = 0; i < prod; i++)
{
printf("1 %d\n", i);
pthread_create(&tid_produce[i], NULL,produce, NULL);
}
for (i = 0; i < con; i++) {
printf("2 %d\n", i);
pthread_create(&tid_consume[i], NULL, consume, NULL);
}
for (i = 0; i < prod; i++) {
printf("3 %d\n", i);
pthread_join(tid_produce[i], NULL);
}
for (i = 0; i < con; i++) {
printf("4 %d\n", i);
pthread_join(tid_consume[i], NULL);
}
exit(0);
}
void *produce(void *arg)
{
for ( ; ; )
{
pthread_mutex_lock(&put.mutex);
if (put.nput >= nitems) {
pthread_mutex_unlock(&put.mutex);
return(NULL); /* array is full, we're done */
}
put.buff[put.nput] = put.nval;
printf ("producer %lu produced :%d \n",pthread_self(), put.buff[put.nput]);
put.nput++;
put.nval++;
printf("outside producer lock\n");
pthread_mutex_unlock(&put.mutex);
*((int *) arg) += 1;
}
}
void *consume(void *arg)
{
int i;
for (i = 0; i < nitems; i++) {
pthread_mutex_lock(&nready.mutex);
while (nready.nready == 0){
pthread_cond_wait(&nready.cond,&nready.mutex);
}
printf ("consumer %lu consumed %d \n", pthread_self(),nready.nready);
nready.nready--;
pthread_mutex_unlock(&nready.mutex);
if (buff[i] != i)
printf("buff[%d] = %d\n", i, buff[i]);
}
return(NULL);
}
*((int *) arg) += 1 inside produce(...) causes the segmentation fault. Because pthread_create(&tid_produce[i], NULL,produce, NULL); passes NULL as arg.
So we need to allocate some memory for arg.
// main
int i, prod, con;
pthread_t tid_produce[MAXNTHREADS], tid_consume[MAXNTHREADS];
int p_arg[MAXNTHREADS]; // <======
// ...
for (i = 0; i < prod; i++)
{
pthread_create(&tid_produce[i], NULL,produce, p_arg+i); // <====
}
I am writing a multi-threaded application that reads a file and seeks for a word in chunks of it a thread has in memory.
A thread needs to asynchronously close other threads looking for that word if it is first to find it.
The problem is when a word is found and other threads are being closed the program does not terminate (in 6 out of 10 executions). I have checked in gdb that one thread does not exit. It happens even when I do not call waitforthreads(n_threads).
// [...]
FILE* f;
pthread_mutex_t mutex;
pthread_t* threads;
int n_threads;
int allread;
// [...]
int main(int argc, char* argv[]) {
// [...]
threads = (pthread_t*) calloc(n_threads, sizeof(pthread_t));
pthread_mutex_init(&mutex, NULL);
runthreads(f, word, n_threads, n_records);
waitforthreads(n_threads);
pthread_mutex_destroy(&mutex);
// [...]
}
void runthreads(FILE* f, char* w, int n_threads, int n_records) {
struct targs_t args = {w, n_records};
for (int i=0; i<n_threads; i++)
pthread_create(&threads[i], NULL, findword, (void*) &args);
}
void waitforthreads(int N) {
for (int i=0; i<N; i++)
if(pthread_join(threads[i], NULL))
exit_(6);
}
void* findword(void* arg) {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
struct targs_t* args = (struct targs_t*) arg;
int max_length = args->n_records * sizeof(record_t);
record_t* records = malloc(max_length);
int found = 0;
while (!allread && !found) {
pthread_mutex_lock(&mutex);
// allread is being set in the function below
// if the whole file has been read
readRecords((char*) records, args->n_records, f);
pthread_mutex_unlock(&mutex);
for (int i=0; i<args->n_records; i++)
if (strlen(records[i].text) == 0) break;
else if (strstr(records[i].text, args->word) != NULL) {
notifyfound(pthread_self(), records[i].id);
found = 1;
break;
}
}
free(records);
return NULL;
}
void notifyfound(pthread_t tid, int id) {
printf("Found: %d (%ld)\n", id, (long) tid);
for (int i=0; i<n_threads; i++)
if (threads[i] && !pthread_equal(threads[i], tid)) {
printf(" closing %ld\n", (long) threads[i]);
pthread_cancel(threads[i]);
}
printf(" finished closing\n");
}
This has to do with cancellation points, although the specifics are hard to come by since you haven't shared a minimal example. My diagnosis is either
6/10 times you have at least one thread waiting for a mutex, and other one in readRecords, which will cancel and not free the mutex. Setup cancellation handlers with pthread_cleanup_push and pthread_cleanup_pop which will free your mutex, and read the manual for pthread_cancel. See related pthread_cleanup_push causes Syntax error for some references.
Some of your threads are not detecting the cancellation - try using pthread_testcancel to setup a guaranteed cancellation point.
Here is some code that fixes these sorts of problems, by adding a cancellation check and mutex cleanup.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
FILE* f;
pthread_mutex_t mutex;
pthread_t* threads;
int n_threads = 3;
int allread;
long int count = 0;
int *thread_ids;
int global_quit = 0;
#define MAX 99999
void waitforthreads(int N) {
printf("waiting for %d threads\n", N);
for (int i=0; i<N; i++)
{
printf("thread %d | %d\n", i, threads[i]);
if(pthread_join(threads[i], NULL))
{
printf("problem\n");
exit(6);
}
}
printf("done.\n");
}
void notifyfound(pthread_t tid, int count) {
printf("%d | %d got big number\n", count, pthread_self());
for (int i=0; i<n_threads; i++)
if (threads[i] && !pthread_equal(threads[i], tid)) {
printf(" closing '%ld'\n", (long) threads[i]);
pthread_cancel(threads[i]);
}
global_quit = 1;
printf(" finished closing\n");
}
void waiting_thread_cleanup(void *arg)
{
pthread_mutex_unlock((pthread_mutex_t *)arg);
}
void* do_thing(void* arg) {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
int* id = (int *)arg;
int quit = 0;
while (!allread) {
pthread_mutex_lock(&mutex);
pthread_cleanup_push(waiting_thread_cleanup, (void *)&mutex); /* must be paired with pop. */
if(count++==MAX)
{
notifyfound(pthread_self(), *id);
quit=1;
}
else if(count % 10000 == 0)
printf("[%d] - %d\n", *id, count);
pthread_testcancel(); /* required to allow for the cancel to ever be 'detected' other functions are sufficient as well. */
pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(1); /* if this isn't here, this will occassionally hand because the mutex isn't freed. */
if(quit==1)
{
printf("%d | %d quitting\n", *id, pthread_self());
break;
}
}
return NULL;
}
void runthreads(FILE* f, int n_threads) {
for (int i=0; i<n_threads; i++)
pthread_create(&threads[i], NULL, do_thing, &(thread_ids[i]));
}
int main(int argc, char* argv[]) {
threads = (pthread_t*) calloc(n_threads, sizeof(pthread_t));
thread_ids = (int*) calloc(n_threads, sizeof(int));
for(int i=0;i<n_threads;i++)
thread_ids[i] = i;
pthread_mutex_init(&mutex, NULL);
runthreads(f, n_threads);
waitforthreads(n_threads);
pthread_mutex_destroy(&mutex);
}
New to C, I was reading here about how to properly pass an argument to a thread. What about if this argument needed to be passed to multiple threads? Where/how should I use free()? Say:
void *foo(void *i) {
int a = *((int *) i);
while(1){
printf("foo running \n");
sleep(1);
}
}
void *bar(void *i) {
int a = *((int *) i);
while(1){
printf("bar running \n");
sleep(1);
}
}
int main() {
pthread_t threads[2];
int i;
for (i = 0; i < 2; i++ ) {
int *arg = malloc(sizeof(*arg));
if ( arg == NULL ) {
fprintf(stderr, "Couldn't allocate memory for thread arg.\n");
exit(1);
}
*arg = i;
pthread_create(&threads[0], NULL, foo, arg);
pthread_create(&threads[1], NULL, bar, arg);
}
for (i = 0; i < 2; i++){
pthread_join(threads[i],NULL);
}
return 0;
}
Is calling free(arg); in main after spawning the threads the same thing / safe?
If all threads needs the exact same argument, and they are not modifying the argument, there's no need to allocate it dynamically at all, instead just declare it as a variable at function scope in the main function. If there's no dynamic allocation, there's no need to free it.
On the other hand if you need separate arguments in a loop like you do, you need to keep track of all arguments, for example using an array:
// Rest of program...
#define NUMBER_OF_ITERATIONS 2
int main(void)
{
int args[NUMBER_OF_ITERATIONS];
pthread_t threads[NUMBER_OF_ITERATIONS][2];
// Create threads
for (unsigned i = 0; i < NUMBER_OF_ITERATIONS; ++i)
{
args[i] = i;
pthread_create(&threads[i][0], NULL, foo, &args[i]);
pthread_create(&threads[i][1], NULL, bar, &args[i]);
}
// Wait for threads to finish
for (unsigned i = 0; i < NUMBER_OF_ITERATIONS; ++i)
{
pthread_join(threads[i][0]);
pthread_join(threads[i][1]);
}
return 0;
}
The program above also solves another problem you have, when you create a total of four threads but only join two.
You need to make sure both threads have finished before calling free(arg).
That means you can do it after you call pthread_join on both threads.
for (i = 0; i < 2; i++){
pthread_join(threads[i],NULL);
}
free(args);
I keep getting a seg fault (core dump) after pthread_join in my program. It prints out the expected result just fine, but seg faults when joining the thread. I have looked at several other discussions on this topic, but none of the suggested solutions seem to work in my case. Here is what my compile command looks like (no compile warnings or errors):
$ gcc -Wall -pthread test.c -o test
Here is the output:
$ ./test
1 2 3 4 5 6 7 8 9 10
Segmentation fault (core dumped)
And here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int array[10];
void *fillArray(int *size) {
int i;
for (i = 0; i < *size; i++) {
array[i] = i+1;
}
return NULL;
}
int main (int argc, char *argv[])
{
int i, rc;
int size = 10;
pthread_t thread;
void *res, *end;
//initialize the array
for (i = 0; i < size; i++) {
array[i] = 0;
}
rc = pthread_create(&thread, NULL, fillArray(&size), &res);
if (rc != 0) {
perror("Cannot create thread");
exit(EXIT_FAILURE);
}
//print the array
for (i = 0; i < size; i++) {
if (array[i] != -1)
printf("%d ", array[i]);
}
printf("\n");
rc = pthread_join(thread, &end);
if (rc != 0) {
perror("Cannot join thread");
exit(EXIT_FAILURE);
}
return 0;
}
Any ideas what could be the cause?
This doesn't compile for me: It fails with
dummy.cpp: In function ‘int main(int, char**)’:
dummy.cpp:29: error: invalid conversion from ‘void*’ to ‘void* (*)(void*)’
dummy.cpp:29: error: initializing argument 3 of ‘int pthread_create(_opaque_pthread_t**, const pthread_attr_t*, void* (*)(void*), void*)’
Which is because you're actually calling fillArray and passing its result to pthread_create, rather than passing the function pointer. I expect your code will need to look more like this (UNTESTED!) : (Note I changed signature of fillArray, created data struct type to pass to fillArray, changed how pthread_create is called)
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int array[10];
struct fillArrayData {
int * array;
int size;
int * result;
};
void *fillArray(void *void_data) {
fillArrayData * data = (fillArray*)void_data;
for (int i = 0; i < data.size; i++) {
data.array[i] = i+1;
}
//You could fill in some return info into data.result here if you wanted.
return NULL;
}
int main (int argc, char *argv[])
{
int i, rc;
int size = 10;
pthread_t thread;
void *res, *end;
//initialize the array
for (i = 0; i < size; i++) {
array[i] = 0;
}
fillArrayData data;
data.array = array;
data.size = 10;
rc = pthread_create(&thread, NULL, fillArray, &data);
if (rc != 0) {
perror("Cannot create thread");
exit(EXIT_FAILURE);
}
//print the array
for (i = 0; i < size; i++) {
if (array[i] != -1)
printf("%d ", array[i]);
}
printf("\n");
rc = pthread_join(thread, &end);
if (rc != 0) {
perror("Cannot join thread");
exit(EXIT_FAILURE);
}
return 0;
}
Error in
Calling function pointer
passing parameter to thread handler
In pthread prototype of pthread_create below
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
1st argument - pthread_variable
2nd argument - thread attrubutes
3rd argument - thread handler(function pointer name)
4th argument - variable need to pass thread handler.
In 4th argument - if two thread want to share single variable, then create global variable, and the pass this variable when creating thread.
sample program:
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}
further details here