I'm working on an exercise (see bold text below) on semaphores and synchronization for my Operative System course. The text of the exercise is this:
Pthread semaphores and mutexes
The C program gen_binary_numbers.c receives on the command line an integer n, and uses recursion to generate and display all binary numbers of n bits.Transform the recursive program into a concurrent one, replacing the recursive procedure with the generation of an appropriate number of processes that display the binary numbers (in any order).
This is my code, actually:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
int num, r, c;
pthread_mutex_t mutex;
void *genBin(void *arg);
int main (int argc, char **argv) {
if (argc != 2) {
fprintf(stdout, "\nUSAGE: %s <n>\n\n", argv[0]);
exit(EXIT_FAILURE);
}
int i;
num = atoi(argv[1]);
c = num;
r = 2;
for (i=1; i<num; i++) {
r=r*2;
}
pthread_mutex_init(&mutex, NULL);
pthread_t* p;
p = malloc(r*sizeof(pthread_t));
for (i=0;i<r;i++) {
if (pthread_create(&p[i], NULL, genBin, &i)) {
fprintf(stderr, "Error creating thread.\n");
exit(EXIT_FAILURE);
}
}
pthread_exit(0);
}
void *genBin (void *arg) {
int x;
int i=0;
x = *((int*)arg);
pthread_mutex_lock(&mutex);
while (i<num) {
if(x!=0) {
fprintf(stdout, "%d", x%2);
}
else {
fprintf(stdout, "0");
}
i++;
x/=2;
}
fprintf(stdout, "\n");
pthread_mutex_unlock(&mutex);
pthread_exit(0);
}
I think that the code should return the right solution, but sometimes the output doesn't return the correct number.
Example of correct output:
./genBin 3
100
101
010
110
001
011
111
000
Example of wrong output (because of duplicates):
./genBin 3
110
110
110
001
011
111
111
000
I think that the problem is in the synchronization between the mutex and the printf.
Is there an alternative solution to avoid confusing results?
Your code contains a race condition. In main, you pass the address of your iteration variable, i, as the thread function's argument. Each new thread then races with the main thread to read the value of i (via the provided pointer) before the main thread increments it. One way you could address that problem would be to use a semaphore to make the main thread wait after creating each thread until that thread has dereferenced its argument.
Also, I don't think you need to use a mutex in genBin(). The only shared data it accesses is stdout, via fprintf(), and that function operates as if it locks an exclusive lock associated with the specified stream. Moreover, with the mutex you get essentially no actual concurrency because each thread holds the mutex locked for almost the complete duration of its execution.
The problem is in this part:
for (i=0;i<r;i++) {
if (pthread_create(&p[i], NULL, genBin, &i)) {
fprintf(stderr, "Error creating thread.\n");
exit(EXIT_FAILURE);
}
}
There's data race because you are passing the address of i to all threads. You could use an temp array to pass the individual number to each thread.
Thanks to everyone! You solved my problem. This is the corrected code:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
int num, r, c;
pthread_mutex_t mutex;
void *genBin(void *arg);
int main (int argc, char **argv) {
if (argc != 2) {
fprintf(stdout, "\nUSAGE: %s <n>\n\n", argv[0]);
exit(EXIT_FAILURE);
}
int i;
int *temp;
num = atoi(argv[1]);
c = num;
r = 2;
for (i=1; i<num; i++) {
r=r*2;
}
temp = malloc(r*sizeof(int));
pthread_mutex_init(&mutex, NULL);
pthread_t* p;
p = malloc(r*sizeof(pthread_t));
for (i=0;i<r;i++) {
temp[i] = i;
}
for (i=0;i<r;i++) {
if (pthread_create(&p[i], NULL, genBin, &temp[i])) {
fprintf(stderr, "Error creating thread.\n");
exit(EXIT_FAILURE);
}
}
for (i=0;i<r;i++) {
if (pthread_join(p[i], NULL)) {
fprintf(stderr, "Error creating thread.\n");
exit(EXIT_FAILURE);
}
}
pthread_mutex_destroy(&mutex);
free(temp);
free(p);
pthread_exit(0);
}
void *genBin (void *arg) {
int x;
int i=0;
int *v;
v = malloc(num*sizeof(int));
x = *((int*)arg);
for (i=0; i<num; i++) {
v[i] = x%2;
x/=2;
}
pthread_mutex_lock(&mutex);
for (i=0; i<num; i++) {
fprintf(stdout, "%d", v[i]);
}
fprintf(stdout, "\n");
pthread_mutex_unlock(&mutex);
free(v);
pthread_exit(0);
}
Related
I'm using Linux to learn semaphore, trnna test the function sem_init. The code seems simple but the error is unexpected, don't know why. Here's the code and the errors is below the code.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include<unistd.h>
#include <stdlib.h>
#define NITER 1000000
int cnt = 0;
sem_t mutex;
sem_init(&mutex,0,1);
void * Count(void * a)
{
int i, tmp;
for(i = 0; i < NITER; i++)
{
sem_wait(&mutex);
tmp = cnt; /* copy the global cnt locally */
tmp = tmp+1; /* increment the local copy */
cnt = tmp; /* store the local value into the global cnt */
sem_post(&mutex);
}
}
int main(int argc, char * argv[])
{
pthread_t tid1, tid2;
if(pthread_create(&tid1, NULL, Count, NULL))
{
printf("\n ERROR creating thread 1");
exit(1);
}
if(pthread_create(&tid2, NULL, Count, NULL))
{
printf("\n ERROR creating thread 2");
exit(1);
}
if(pthread_join(tid1, NULL)) /* wait for the thread 1 to finish */
{
printf("\n ERROR joining thread");
exit(1);
}
if(pthread_join(tid2, NULL)) /* wait for the thread 2 to finish */
{
printf("\n ERROR joining thread");
exit(1);
}
if (cnt < 2 * NITER)
printf("\n BOOM! cnt is [%d], should be %d\n", cnt, 2*NITER);
else
printf("\n OK! cnt is [%d]\n", cnt);
pthread_exit(NULL);
}
my english is bad, if anything is hard to understand please tell me and ill respond you as soon as possible!thx
You can declare variables outside the main and the other function which mean that the variable is global .
But to call the function sem_init(&mutex,0,1); you should do it from the main or from another function. In your case , you have to do it in the main.
After moving the sem_init inside the main it compile
nabil#DESKTOP-8ECTID4:~/stackoverflow$ gcc bad.c -o bad -lpthread
nabil#DESKTOP-8ECTID4:~/stackoverflow$
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);
}
Learning about pthreads, but I'm having trouble getting them created. Here is my output and the gdb information:
In main(), creating thread 1
ERROR: return code from pthread_create() is 22 for thread 1
In main(), creating thread 2
ERROR: return code from pthread_create() is 22 for thread 2
In main(), creating thread 3
ERROR: return code from pthread_create() is 22 for thread 3
In main(), creating thread 4
ERROR: return code from pthread_create() is 22 for thread 4
In main(), creating thread 5
ERROR: return code from pthread_create() is 22 for thread 5
Program received signal SIGSEGV, Segmentation fault. 0xb7fb4d8a in
pthread_join (threadid=76038327, thread_return=0x0)
at pthread_join.c:46 46 pthread_join.c: No such file or directory.
And here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#define SBUFSIZE 1025
char errorstr[SBUFSIZE];
FILE* inputfp[5];
void* f(void* inpFile) {
fprintf(stderr, "%s\n", (char*)inpFile);
return NULL;
}
int main (int argc, char* argv[]) {
int i;
/* Thread Variables */
pthread_attr_t attr;
pthread_t *th[argc-2]; //one thread for each input file
/* allocate memory for the threads */
for (i = 0; i < (argc-2); i++) {
th[i] = (pthread_t *) malloc(sizeof(pthread_t));
inputfp[i] = fopen(argv[i], "r");
if (!inputfp[i]) {
sprintf(errorstr, "Error Opening Input File: %s", argv[i]);
perror(errorstr);
}
}
/* Create one thread for each input file */
for (i = 1; i < (argc - 1); i++) {
fprintf (stderr, "In main(), creating thread %1d\n", i);
int rc = pthread_create (th[i], &attr, f, inputfp[i-1]);
if (rc) {
printf("ERROR: return code from pthread_create() is %d for thread %d\n",
rc, i);
}
}
/* wait for the threads to finish */
for (i = 1; i < (argc - 1); i++) {
pthread_join(*th[i], 0);
}
return EXIT_SUCCESS;
}
I'm missing something, but I don't know what. Can anyone help? Thank you!
EDIT: Here is how I changed the code per the suggestion from Joachim Pileborg. I'm still getting error 22 returning from pthread_create(), but the SIGSEGV error on pthread_join is no longer occurring.
Anyone have any suggestions about how I can get the pthread_create() to return 0 (indicating a successful thread creation)? Thanks again!
int main (int argc, char* argv[]) {
int i;
/* Thread Variables */
pthread_attr_t attr;
pthread_t *th[argc-2]; //one thread for each input file
/* allocate memory for the threads */
for (i = 0; i < (argc-2); i++) {
th[i] = (pthread_t *) malloc(sizeof(pthread_t));
printf("%s\n", argv[i+1]);
inputfp[i] = fopen(argv[i+1], "r");
if (!inputfp[i]) {
sprintf(errorstr, "Error Opening Input File: %s", argv[i]);
perror(errorstr);
}
}
/* Create one thread for each input file */
for (i = 0; i < (argc - 2); i++) {
fprintf (stderr, "In main(), creating thread %1d\n", i);
int rc = pthread_create (th[i], &attr, f, inputfp[i]);
if (rc) {
printf("ERROR: return code from pthread_create() is %d for thread %d\n",
rc, i);
}
}
/* wait for the threads to finish */
for (i = 0; i < (argc - 2); i++) {
pthread_join(*th[i], 0);
}
return EXIT_SUCCESS;
}
You have one loop where you loop from zero to argc - 3, and uses the correct indexes (zero to "size of array minus one".
Then you have two loops where you loop from one to argc - 2, and use indexes from one to "size of array".
You should use the same loop as the first one in all three places.