I am trying to create a semaphore and practicing by using this simple program, though I am getting a bunch of deprecated warnings when compiling on macos. I have been looking and having trouble finding a solution to get the semaphore to work for macos.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#define THREAD_NUM 4
sem_t semaphore;
void* routine(void* args) {
sem_wait(&semaphore);
sleep(1);
printf("Hello from thread %d\n", *(int*)args);
sem_post(&semaphore);
free(args);
}
int main(int argc, char *argv[]) {
pthread_t th[THREAD_NUM];
sem_init(&semaphore, 0, 1);
int i;
for (i = 0; i < THREAD_NUM; i++) {
int* a = malloc(sizeof(int));
*a = i;
if (pthread_create(&th[i], NULL, &routine, a) != 0) {
perror("Failed to create thread");
}
}
for (i = 0; i < THREAD_NUM; i++) {
if (pthread_join(th[i], NULL) != 0) {
perror("Failed to join thread");
}
}
sem_destroy(&semaphore);
return 0;
}
I am expecting the threads to be created for the routine function where 4 threads exist for 4 void* routine(). It should
printf("Hello from thread") every second starting from thread 0 and going to 3. What is actually happening is all the printf statements get outputed to the console after 1 second at the same time.
Output:
Hello from thread 0
Hello from thread 1
Hello from thread 2
Hello from thread 3
Compiler information:
test.c:18:1: warning: non-void function does not return a value [-Wreturn-type]
}
^
test.c:22:5: warning: 'sem_init' is deprecated [-Wdeprecated-declarations]
sem_init(&semaphore, 0, 4);
^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/semaphore.h:55:42: note: 'sem_init' has been explicitly marked deprecated here
int sem_init(sem_t *, int, unsigned int) __deprecated;
^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/cdefs.h:204:40: note: expanded from macro '__deprecated'
#define __deprecated __attribute__((__deprecated__))
^
test.c:37:5: warning: 'sem_destroy' is deprecated [-Wdeprecated-declarations]
sem_destroy(&semaphore);
^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/semaphore.h:53:26: note: 'sem_destroy' has been explicitly marked deprecated here
int sem_destroy(sem_t *) __deprecated;
^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/cdefs.h:204:40: note: expanded from macro '__deprecated'
#define __deprecated __attribute__((__deprecated__))
^
3 warnings generated.
I am expecting the threads to be created for the routine function where 4 threads exist for 4 void* routine(). It should printf("Hello from thread") every second starting from thread 0 and going to 3.
I would expect that, too, on any machine that provides POSIX-conforming pthreads, POSIX semaphores, and sleep(). Especially if you resolve the first of the warnings -- for example, by adding return NULL; at the end of function routine().
My expectation is fulfilled on my Linux test machine. However, there are comments around various parts of the web suggesting that MacOS does not support unnamed semaphores, which is what you are trying to use by calling sem_init(). As I understand it, this is the significance of the deprecation warnings you report -- the functions are there, but (I guess) they don't actually work.
If indeed MacOS's sem_init() is non-functional, then calls to it should return an error code. You don't know whether that's happening, because you don't check for it. Always check your functions' error indicators if in fact you care whether they succeeded (and here, you certainly do).
One possible workaround that does not require abandoning POSIX interfaces would be to switch to named semaphores instead of unnamed ones. That would involve using sem_open() and sem_close() instead of sem_init() and sem_destroy().
What is actually happening is all the printf statements get outputed to the console after 1 second at the same time.
That certainly sounds like the semaphore is not working. Your threads are working, because you get the output at all, and they are running in parallel, because their sleep()s all expire at about the same time. Again, check the error indicators of your function calls (their return values for all library functions in the example code), as this will often clue you in when something does not work as you expect, whether because of something wrong with your code or because erroneous data or runtime environment.
Related
This question already has answers here:
How to "multithread" C code
(13 answers)
Closed 3 years ago.
This is my first contact with c and Multithreading.
I look for an example how to use it in Basic.
This is what I want to to parallel:
PseudoCode that should run on different Threads
Code1
int main(){
int i =1000;
while(i>0){
i--;
}
}
Code2
int main(){
int x =0;
if(i%5){
x++;
}
}
I also didn't know how to pass Objects, maybe someone can explaine this too.
Please use only lowercase in C to declaring variables and functions
as struct,typeof,sizeof,int,char,void,for,while,etc....
EDIT:
Sorry for not to understand "I thought you need help to do that code in C"
Now i know that you want multi-threading functions to do two jobs or more at the same time without waiting for other to finish.
Okay, to do that you have to
include pthread.h which means POSIX Thread
Note: you should notice from this name that this library for Linux OS only
and you compile it with gcc compiler
declare variable pthread to for example: tid in your main() as the most popular name
Create your function in void *() and type stuff whatever it does then create your thread in main() and assign it your function through that code:
pthread_create(&tid, NULL, MyThread, NULL);
pthread_create() arguments:
A pointer to a pthread_t structure that we created to fill it with the upcoming arguments.
A pointer to a pthread_attr_t with parameters for the thread. You can safely just pass NULL most of the time.
Note: The pthread_attr_t > "arg 2" should be treated as opaque: any access to
the object other than via pthreads functions is nonportable and
produces undefined results.
Take the function that you created as thread and shall be with no return and
points to >> void, that's why we created void *()
Note: Type only the name of function without (), you will know why in the next argument
Here you passing your arguments to your function!, if there's no arguments just pass NULL
Example Code:
#include <stdio.h>
#include <pthread.h>
int i=0,x=0; //Initialize our variables
void *MyThread(void *ANYarg) //arguments must be a pointers to point from `pthread_create` with `NULL` if no need
{
while(1) //background thread
{
i++;
x++;
}
return NULL;
}
int main()
{
char *input;
pthread_t tid; //Declare a thread
pthread_create(&tid, NULL, MyThread, NULL); //Create the thread
while(1) //Printing thread , Uncover increamting of variables
{
scanf("%s",&input); //whenever you input a value
printf("i: %d, x: %d\n",i,x);//will print the i,x values now
}
return 0;
}
Note: You should at least create one pointer variable specifically to your thread function cause fourth argument of pthread_create() need at least one to pass the NULL value
You can wait for an thread to finish instead of doing work at the same time through that code line:
pthread_join(tid, NULL);
Should return 0 when success
An Example:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *MyCoolthread(void *vargp)
{
printf("Yes..see me printing success after 3 seconds \n");
sleep(3);
printf("Success! \n");
return NULL;
}
int main()
{
pthread_t tid;
printf("Hello, are you there? \n");
sleep(1);
pthread_create(&tid, NULL, MyCoolthread, NULL);
pthread_join(tid, NULL);
printf("Yup i see!\n");
return 0;
}
Try to comment pthread_join(tid, NULL); with // to see what happens
and to terminate your thread is through code line:
pthread_exit(&tid);
Doesn't return to its caller any value
Edit: I noticed now that you use windows so i advice you to dual boot with Ubuntu instead if you really interested in C
otherwise you can use multi-threading in windows.h header that called winapi library but i'm not expert in so you can find an simple example here and you should mentioned in your post that you want for windows by the way you can edit to improve it
I tried my best to get it clear, hope it helps.
I'm porting a software from an embedded computer to a Linux machine. (Ubuntu 14.04 or Raspbian (raspberry pi))
The original program was using setjmp/longjmp to handle timeout and CTRL+C event. It was running on a Microcontroller with a single main (one thread).
I'm trying to have a similar behaviour while using threads (pthreads).
The idea is that I want either a timeout or a CTRL+C to restart an infinite loop.
The original code was doing something like the code below. I don't mind to drop the setjmp/longjmp by something else. (ex: try/catch or signal or pthread_kill, conditional variable, etc..)
Any idea how to implement similar behavior with C/C++ ?
Here is the code which seems to partially work and is probably not recommended/broken:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <setjmp.h>
// Define
#define TICK_NS_TIME (10000000) // 0.01 sec = 10 ms (100 times per second)
#define NS_PER_SEC (1000000000) // Nano sec per second.
#define TICK_PER_SEC (NS_PER_SEC/TICK_NS_TIME) // Number of tick per second (Ex:100)
#define TIMEOUT_COUNT (30*TICK_PER_SEC) // 30 seconds timeout (with 100 tick per second)
// Env set/long jmp
#define ENV_SZ (2)
#define ENV_TIMEOUT (0)
#define ENV_CTRLC (1)
static jmp_buf env[ENV_SZ];
// Variables
int timeout_val;
// sig handler.
void signal_handler(int signo)
{
pthread_t self = pthread_self();
printf("Thread %lu in signal handler\n", (long)self);
if (signo == SIGINT) {
longjmp(env[ENV_CTRLC], 1); // Q?: Is it in the same thread ? (Never, Always, Sometimes?)
}
else
{
printf("Other signal received..quitting."); // Ex: kill -9 pid
exit(0);
}
}
// thread timer function
void* timer_function(void* in_param)
{
// Loop approx 100x per second.
for (;;) {
nanosleep((const struct timespec[]){{0, TICK_NS_TIME }}, NULL); // Sleep 10 ms seconds.
if (timeout_val) {
if (!--timeout_val) {
longjmp(env[ENV_TIMEOUT], 1); // longjmp when timer reaches 0. (Q?: Is this valid with multithread?)
}
}
}
}
// main
int main(int argc, char **argv)
{
int i;
int val;
struct sigaction actions;
pthread_t thread;
setvbuf (stdout, NULL, _IONBF, 0); // Make sure stdout is not buffered (ex:printf, etc.)
printf("[Program started]\r\n");
memset(&actions, 0, sizeof(actions));
sigemptyset(&actions.sa_mask);
actions.sa_flags = 0;
actions.sa_handler = signal_handler;
val = sigaction(SIGINT, &actions, NULL);
pthread_create(&thread, NULL, timer_function, NULL); // timer thread for example
printf("[Timer thread started]\r\n");
// setting env.
val = setjmp(env[ENV_TIMEOUT]);
if (val!=0){ printf("[JMP TIMEOUT]\r\n"); }
val = setjmp(env[ENV_CTRLC]);
if (val!=0){ printf("[JMP CTRLC]\r\n"); }
// main loop
timeout_val = TIMEOUT_COUNT;
i = 0;
for (;;)
{
i++;
if (i > 10){ i = 0; printf("[%d]", timeout_val/TICK_PER_SEC); } // Number of seconds before time out.
sleep(1);
printf(".");
}
printf("Main completed\n");
return 0;
}
//Compile: g++ -pthread main.cpp -o main
Suggestion for alternative implementation would be great since I'm new to programming with threads !
setjmp() saves the information required to restore the calling environment. longjmp() can then restore this environment, but only within the same thread.
The C11 standard is explicit about the constraint of having the same thread:
7.13.2.1/2 If there has been no such invocation (i.e: of a previous setjmp), or if the invocation was from another thread of
execution, or if the function containing the invocation of the
setjmp macro has terminated execution in the interim, or if the
invocation of the setjmp macro was within the scope of an identifier
with variably modified type and execution has left that scope in the
interim, the behavior is undefined.
In fact, setjmp/longjmp are generally implemented by saving the stack pointer so that restoring it makes sense only int the same execution context.
Alternative
Unless I've missed something, you use the second thread only to act as a timer. You could instead get rid of your POSIX pthread, and use a timer signal activated with POSIX timer_create().
But be aware that using setjmp/longjmp from a signal handler (so already in your original code for CTRL+C) is tricky, as explained in this SO answer. So you'd consider sigsetjmp/siglongjmp.
For the records: C or C++ ?
Your question is tagged C. But you mention c++ try and catch. So for the sake of completeness:
in C++ setjmp should be replaced by a try/catch and the longjmp by throwing an exception. setjmp/longjmp are supported in C++ only if unwinding the stack wouldn't require invocation of any non-trivial destructor (see C++ standard, 18.10/4).
the exceptions are not propagated across the threads, unless catched and explicitely rethrown using std::rethrow_exception(). It's delicate, so refer to this SO question for for additional details. But it's possible and could solve your issue.
Hi fellow programmers,
I wanted to write a simple multi-threaded program in C with pthread, but somehow the pthread_join seems to hang.
It seems happens not always, sometimes everything is running fine, next time it't hanging againg, usually on the first thread.
I already minimized the code to the bare minimum, so that i can exclude other problems. In the full code the threads did some computations, of course. But the problems still persists even with this very reduced code. And on more than one machine, with different OS'es.
strace shows me that the hanging has something to do with a FUTEX_WAIT, the full last lines:
write(1, "Joining Thread 0...\n", 20Joining Thread 0...
) = 20
futex(0x7fff61718a20, FUTEX_WAIT, 1634835878, NULL
I tried to debug it with gdb, but my poor debugging stills are very limited, especially with multi-threaded programs.
I also tried to compile it using different C-standards (C99 and Ansi) and both pthread parameters (-lpthread, -pthread), but the problem still persists.
The (reduced) code monte2.c:
#include <stdio.h>
#include <pthread.h>
void *monte(struct MonteArgs *args) {
pthread_exit(NULL);
}
int main(int argc, char **argv) {
int numThreads, numSamples;
int i;
if (argc != 3) {
printf("Usage: monte threads samples\n");
exit(1);
}
numThreads = atoi(argv[1]);
pthread_t threads[numThreads];
numSamples = atoi(argv[2]);
for (i=0; i<numThreads; i++) {
if (pthread_create(&threads[i], NULL, monte, NULL)) {
printf("Error Creating Thread %d!\n", i);
return 1;
}
}
for (i=0; i<numThreads; i++){
printf("Joining Thread %d...\n", i);
pthread_join(&threads[i], NULL);
}
printf("End!\n");
fflush(stdout);
return(0);
}
I compile with
gcc monte2.c -lpthread -o monte
and run with
./monte2 3 100
where the first argument is the number of threads, and the second is actually not needed for the reduced code.
It's been a while since I've done multi-threaded C, but you shouldn't ignore compiler warnings :-). Compile with -Wall.
You should be seeing a warning like this:
note: expected 'pthread_t' but argument is of type 'pthread_t *'
int WINPTHREAD_API pthread_join(pthread_t t, void **res);
You are passing a pthread_t* when you should be passing pthread_t.
Refer to the pthread_join docs: http://man7.org/linux/man-pages/man3/pthread_join.3.html
I was trying to implement a multi-threaded program using binary semaphore. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
int g = 0;
sem_t *semaphore;
void *myThreadFun(void *vargp)
{
int myid = (int)vargp;
static int s = 0;
sem_wait(semaphore);
++s; ++g;
printf("Thread ID: %d, Static: %d, Global: %d\n", myid, s, g);
fflush(stdout);
sem_post(semaphore);
pthread_exit(0);
}
int main()
{
int i;
pthread_t tid;
if ((semaphore = sem_open("/semaphore", O_CREAT, 0644, 3))==SEM_FAILED) {
printf("semaphore initialization failed\n");
}
for (i = 0; i < 3; i++) {
pthread_create(&tid, NULL, myThreadFun, (void *)i);
}
pthread_exit(NULL);
return 0;
}
Now, when I opened the sempahore, I made the count 3. I was expecting that this wouldnt work, and I would get race condition, because each thread is now capable of decrementing the count.
Is there something wrong with the implementation? Also, if I make the count 0 during sem_open, wouldnt that initiate a deadlock condition, because all the threads should be blocked on sem_wait.
Now, when I opened the sempahore, I made the count 3. I was expecting that this wouldnt work, and I would get race condition, because each thread is now capable of decrementing the count.
And how do you judge that there isn't any race? Observing output consistent with what you could rely upon in the absence of a data race in no way proves that there isn't a data race. It merely fails provide any evidence of one.
However, you seem to be suggesting that there would be a data race inherent in more than one thread concurrently performing a sem_wait() on a semaphore whose value is initially greater than 1 (otherwise which counter are you talking about?). But that's utter nonsense. You're talking about a semaphore. It's a synchronization object. Such objects and the functions that manipulate them are the basis for thread synchronization. They themselves are either completely thread safe or terminally buggy.
Now, you are correct that you open the semaphore with an initial count sufficient to avoid any of your threads blocking in sem_wait(), and that therefore they can all run concurrently in the whole body of myThreadFun(). You have not established, however, that they in fact do run concurrently. There are several reasons why they might not do. If they do run concurrently, then the incrementing of shared variables s and g is indeed of concern, but again, even if you see no signs of a data race, that doesn't mean there isn't one.
Everything else aside, the fact that your threads all call sem_wait(), sem_post(), and printf() induces some synchronization in the form of memory barriers, which would reduce the likelihood of observing anomalous effects on s and g. sem_wait() and sem_post() must contain memory barriers in order to function correctly, regardless of the semaphore's current count. printf() calls are required to use locking to protect the state of the stream from corruption in multi-threaded programs, and it is reasonable to suppose that this will require a memory barrier.
Is there something wrong with the implementation?
Yes. It is not properly synchronized. Initialize the semaphore with count 1 so that the modifications of s and g occur only while exactly one thread has the semaphore locked.
Also, if I make the count 0 during sem_open, wouldnt that initiate a deadlock condition, because all the threads should be blocked on sem_wait.
If the semaphore has count 0 before any of the additional threads are started, then yes. It is therefore inappropriate to open the semaphore with count 0, unless you also subsequently post to it before starting the threads. But you are using a named semaphore. These persist until removed, and you never remove it. The count you specify to sem_open() has no effect unless a new semaphore needs to be created; when an existing semaphore is opened, its count is unchanged.
Also, do have the main thread join all the others before it terminates. It's not inherently wrong not to do so, but in most cases it's required for the semantics you want.
I'll get to the code in a bit that proves you had a race condition. I'll add a couple of different ways to trigger it so you can see how this works. I'm doing this on Linux and passing -std=gnu99 as a param to gcc ie
gcc -Wall -pedantic -lpthread -std=gnu99 semaphore.c -o semtex
Note. In your original example (assuming Linux) one fatal mistake you had was not removing the semaphore. If you run the following command you might see some of these sitting around on your machine
ls -la /dev/shm/sem.*
You need to make sure that there are no old semaphore sitting on the filesystem before running your program or you end up picking up the last settings from the old semaphore. You need to use sem_unlink to clean up.
To run it please use the following.
rm /dev/shm/sem.semtex;./semtex
I'm deliberately making sure that the semaphore is not there before running because if you have a DEADLOCK it can be left around and that causes all sorts of problems when testing.
Now, when I opened the sempahore, I made the count 3. I was expecting
that this wouldn't work, and I would get race condition, because each
thread is now capable of decrementing the count.
You had a race condition but sometimes C is so damned fast things can appear to work because your program can get everything it needs done in the time the OS has allocated to the thread ie the OS didn't preempt it at an important point.
This is one of those cases, the race condition is there you just need to squint a little bit to see it. In the following code you can tweak some parameters to see the a deadlock, correct usage and Undefined Behavior.
#define INITIAL_SEMAPHORE_VALUE CORRECT
The value INITIAL_SEMAPHORE_VALUE can take three values...
#define DEADLOCK 0
#define CORRECT 1
#define INCORRECT 2
I hope they're self explanatory. You can also use two methods to cause the race condition to blow up the program.
#define METHOD sleep
Set the METHOD to spin and you can play with the SPIN_COUNT and find out how many times the loop can run before you actually see a problem, this is C, it can get a lot done before it gets preempted. The code has most of the rest of the information you need in it.
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define DEADLOCK 0 // DEADLOCK
#define CORRECT 1 // CORRECT
#define INCORRECT 2 // INCORRECT
/*
* Change the following values to observe what happen.
*/
#define INITIAL_SEMAPHORE_VALUE CORRECT
//The next value provides to two different ways to trigger the problem, one
//using a tight loop and the other using a system call.
#define METHOD sleep
#if (METHOD == spin)
/* You need to increase the SPIN_COUNT to a value that's big enough that the
* kernel preempts the thread to see it fail. The value set here worked for me
* in a VM but might not work for you, tweak it. */
#define SPIN_COUNT 1000000
#else
/* The reason we can use such a small time for USLEEP is because we're making
* the kernel preempt the thread by using a system call.*/
#define USLEEP_TIME 1
#endif
#define TOT_THREADS 10
static int g = 0;
static int ret = 1729;
sem_t *semaphore;
void *myThreadFun(void *vargp) {
int myid = (int)vargp;
int w = 0;
static int s = 0;
if((w = sem_wait(semaphore)) != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
abort();
};
/* This is the interesting part... Between updating `s` and `g` we add
* a delay using one of two methods. */
s++;
#if ( METHOD == spin )
int spin = 0;
while(spin < SPIN_COUNT) {
spin++;
}
#else
usleep(USLEEP_TIME);
#endif
g++;
if(s != g) {
fprintf(stderr, "Fatal Error: s != g in thread: %d, s: %d, g: %d\n", myid, s, g);
abort();
}
printf("Thread ID: %d, Static: %d, Global: %d\n", myid, s, g);
// It's a false sense of security if you think the assert will fail on a race
// condition when you get the params to sem_open wrong It might not be
// detected.
assert(s == g);
if((w = sem_post(semaphore)) != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
abort();
};
return &ret;
}
int main(void){
int i;
void *status;
const char *semaphore_name = "semtex";
pthread_t tids[TOT_THREADS];
if((semaphore = sem_open(semaphore_name, O_CREAT, 0644, INITIAL_SEMAPHORE_VALUE)) == SEM_FAILED) {
fprintf(stderr, "Fatal Error: %s\n", strerror(errno));
abort();
}
for (i = 0; i < TOT_THREADS; i++) {
pthread_create(&tids[i], NULL, myThreadFun, (void *) (intptr_t) i);
}
for (i = 0; i < TOT_THREADS; i++) {
pthread_join(tids[i], &status);
assert(*(int*)status == 1729);
}
/*The following line was missing from your original code*/
sem_unlink(semaphore_name);
pthread_exit(0);
}
For some reason I thought that calling pthread_exit(NULL) at the end of a main function would guarantee that all running threads (at least created in the main function) would finish running before main could exit. However when I run this code below without calling the two pthread_join functions (at the end of main) explicitly I get a segmentation fault, which seems to happen because the main function has been exited before the two threads finish their job, and therefore the char buffer is not available anymore. However when I include these two pthread_join function calls at the end of main it runs as it should. To guarantee that main will not exit before all running threads have finished, is it necessary to call pthread_join explicitly for all threads initialized directly in main?
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <semaphore.h>
#define NUM_CHAR 1024
#define BUFFER_SIZE 8
typedef struct {
pthread_mutex_t mutex;
sem_t full;
sem_t empty;
char* buffer;
} Context;
void *Reader(void* arg) {
Context* context = (Context*) arg;
for (int i = 0; i < NUM_CHAR; ++i) {
sem_wait(&context->full);
pthread_mutex_lock(&(context->mutex));
char c = context->buffer[i % BUFFER_SIZE];
pthread_mutex_unlock(&(context->mutex));
sem_post(&context->empty);
printf("%c", c);
}
printf("\n");
return NULL;
}
void *Writer(void* arg) {
Context* context = (Context*) arg;
for (int i = 0; i < NUM_CHAR; ++i) {
sem_wait(&context->empty);
pthread_mutex_lock(&(context->mutex));
context->buffer[i % BUFFER_SIZE] = 'a' + (rand() % 26);
float ranFloat = (float) rand() / RAND_MAX;
if (ranFloat < 0.5) sleep(0.2);
pthread_mutex_unlock(&(context->mutex));
sem_post(&context->full);
}
return NULL;
}
int main() {
char buffer[BUFFER_SIZE];
pthread_t reader, writer;
Context context;
srand(time(NULL));
int status = 0;
status = pthread_mutex_init(&context.mutex, NULL);
status = sem_init(&context.full,0,0);
status = sem_init(&context.empty,0, BUFFER_SIZE);
context.buffer = buffer;
status = pthread_create(&reader, NULL, Reader, &context);
status = pthread_create(&writer, NULL, Writer, &context);
pthread_join(reader,NULL); // This line seems to be necessary
pthread_join(writer,NULL); // This line seems to be necessary
pthread_exit(NULL);
return 0;
}
If that is the case, how could I handle the case where plenty of identical threads (like in the code below) would be created using the same thread identifier? In that case, how can I make sure that all the threads will have finished before main exits? Do I really have to keep an array of NUM_STUDENTS pthread_t identifiers to be able to do this? I guess I could do this by letting the Student threads signal a semaphore and then let the main function wait on that semaphore, but is there really no easier way to do this?
int main()
{
pthread_t thread;
for (int i = 0; i < NUM_STUDENTS; i++)
pthread_create(&thread,NULL,Student,NULL); // Threads
// Make sure that all student threads have finished
exit(0);
}
pthread_exit() is a function called by a thread to terminate its own execution. For the situation you've given it is not to be called from your main program thread.
As you have figured out, pthread_join() is the correct means to wait for the completion of a joinable thread from main().
Also as you've figured out, you need to maintain the value returned from pthread_create() to pass to pthread_join().
What this means is that you cannot use the same pthread_t variable for all the threads you create if you intend to use pthread_join().
Rather, build an array of pthread_t so that you have a copy of each thread's ID.
Quite aside from whether the program should or should not terminate when the main thread calls pthread_exit, pthread_exit says
The pthread_exit() function terminates
the calling thread
And also:
After a thread has terminated, the
result of access to local (auto)
variables of the thread is undefined.
Since the context is an automatic variable of main(), your code can fall over before it even gets to the point of testing what you want it to test...
A mini saga
You don't mention the environment in which you are running the original code. I modified your code to use nanosleep() (since, as I mentioned in a comment to the question, sleep() takes an integer and therefore sleep(0.2) is equivalent to sleep(0)), and compiled the program on MacOS X 10.6.4.
Without error checking
It works fine; it took about 100 seconds to run with the 0.5 probability factor (as you'd expect; I changed that to 0.05 to reduce the runtime to about 10 seconds), and generated a random string - some of the time.
Sometimes I got nothing, sometimes I got more and sometimes I got less data. But I didn't see a core dump (not even with 'ulimit -c unlimited' to allow arbitrarily large core dumps).
Eventually, I applied some tools and got to see that I always got 1025 characters (1024 generated plus a newline), but quite often, I got 1024 ASCII NUL characters. Sometimes they'd appear in the middle, sometimes at the beginning, etc:
$ ./pth | tpipe -s "vis | ww -w64" "wc -c"
1025
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000
\000\000\000\000\000\000\000\000ocriexffwgdvdvyfitjtvlzcoffhusjo
zyacniffpsfswesgrkuxycsubufamxxzkrkqnwvsxcbmktodessyohixsmuhdovt
hhertqjjinzoptcuqzertybicrzaeyqlyublbfgutcdvftwkuvxhouiuduoqrftw
xjkgqutpryelzuaerpsbotwyskaflwofseibfqntecyseufqxvzikcyeeikjzsye
qxhjwrjmunntjwhohqovpwcktolcwrvmfvdfsmkvkrptjvslivbfjqpwgvroafzn
fkjumqxjbarelbrdijfrjbtiwnajeqgnobjbksulvcobjkzwwifpvpmpwyzpwiyi
cdpwalenxmocmtdluzouqemmjdktjtvfqwbityzmronwvulfizpizkiuzapftxay
obwsfajcicvcrrjehjeyzsngrwusbejiovaaatyzouktetcerqxjsdpswixjpege
blxscdebfsptxwvwsllvydipovzmnrvoiopmqotydqaujwdykidmwzitdsropguv
vudyfiaaaqueyllnwudfpplcfbsngqqeyucdawqxqzczuwsnaquofreilzvdwbjq
ksrouwltvaktpdrvjnqahpdqdshmmvntspglexggshqbjrvxceaqlfnukedxzlms
cnapdtgtcoyhnglojbjnplowericrzbfulvrobfn
$
(The 'tpipe' program is like 'tee' but it writes to pipes instead of files (and to standard output unless you specify the '-s' option); 'vis' comes from 'The UNIX Programming Environment' by Kernighan & Pike; 'ww' is a 'word wrapper' but there aren't any words here so it brute force wraps at width 64.)
The behaviour I was seeing was highly indeterminate - I'd get different results on each run. I even replaced the random characters with the alphabet in sequence ('a' + i % 26), and was still getting odd behaviour.
I added some debug printing code (and a counter to the contex), and it was clear that the semaphore context->full was not working properly for the reader - it was being allowed to go into the mutual exclusion before the writer had written anything.
With error checking
When I added error checking to the mutex and semaphore operations, I found that:
sem_init(&context.full) failed (-1)
errno = 78 (Function not implemented)
So, the weird outputs are because MacOS X does not implement sem_init(). It's odd; the sem_wait() function failed with errno = 9 (EBADF 'Bad file descriptor'); I added the checks there first. Then I checked the initialization...
Using sem_open() instead of sem_init()
The sem_open() calls succeed, which looks good (names "/full.sem" and "/empty.sem", flags O_CREAT, mode values of 0444, 0600, 0700 at different times, and initial values 0 and BUFFER_SIZE, as with sem_init()). Unfortunately, the first sem_wait() or sem_post() operation fails with errno = 9 (EBADF 'Bad file descriptor') again.
Morals
It is important to check error conditions from system calls.
The output I see is non-deterministic because the semaphores don't work.
That doesn't alter the 'it does not crash without the pthread_join() calls' behaviour.
MacOS X does not have a working POSIX semaphore implementation.
There is no need for calling pthread_join(reader,NULL); at all if Context and buffer are declared with static storage duration (as already pointed out by Steve Jessop, caf and David Schwartz).
Declaring Context and buffer static also makes it necessary to change Context *context to Context *contextr or Context *contextw respectively.
In addition, the following rewrite called pthread_exit.c replaces sem_init() with sem_open() and uses nanosleep() (as suggested by Jonathan Leffler).
pthread_exit was tested on Mac OS X 10.6.8 and did not output any ASCII NUL characters.
/*
cat pthread_exit.c (sample code to test pthread_exit() in main())
source:
"pthreads in C - pthread_exit",
http://stackoverflow.com/questions/3330048/pthreads-in-c-pthread-exit
compiled on Mac OS X 10.6.8 with:
gcc -ansi -pedantic -std=gnu99 -Os -Wall -Wextra -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes \
-Wmissing-prototypes -Wformat=2 -l pthread -o pthread_exit pthread_exit.c
test with:
time -p bash -c './pthread_exit | tee >(od -c 1>&2) | wc -c'
*/
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
#include <semaphore.h>
#include <time.h>
void *Reader(void* arg);
void *Writer(void* arg);
// #define NUM_CHAR 1024
#define NUM_CHAR 100
#define BUFFER_SIZE 8
typedef struct {
pthread_mutex_t mutex;
sem_t *full;
sem_t *empty;
const char *semname1;
const char *semname2;
char* buffer;
} Context;
static char buffer[BUFFER_SIZE];
static Context context;
void *Reader(void* arg) {
Context *contextr = (Context*) arg;
for (int i = 0; i < NUM_CHAR; ++i) {
sem_wait(contextr->full);
pthread_mutex_lock(&(contextr->mutex));
char c = contextr->buffer[i % BUFFER_SIZE];
pthread_mutex_unlock(&(contextr->mutex));
sem_post(contextr->empty);
printf("%c", c);
}
printf("\n");
return NULL;
}
void *Writer(void* arg) {
Context *contextw = (Context*) arg;
for (int i = 0; i < NUM_CHAR; ++i) {
sem_wait(contextw->empty);
pthread_mutex_lock(&(contextw->mutex));
contextw->buffer[i % BUFFER_SIZE] = 'a' + (rand() % 26);
float ranFloat = (float) rand() / RAND_MAX;
//if (ranFloat < 0.5) sleep(0.2);
if (ranFloat < 0.5)
nanosleep((struct timespec[]){{0, 200000000L}}, NULL);
pthread_mutex_unlock(&(contextw->mutex));
sem_post(contextw->full);
}
return NULL;
}
int main(void) {
pthread_t reader, writer;
srand(time(NULL));
int status = 0;
status = pthread_mutex_init(&context.mutex, NULL);
context.semname1 = "Semaphore1";
context.semname2 = "Semaphore2";
context.full = sem_open(context.semname1, O_CREAT, 0777, 0);
if (context.full == SEM_FAILED)
{
fprintf(stderr, "%s\n", "ERROR creating semaphore semname1");
exit(EXIT_FAILURE);
}
context.empty = sem_open(context.semname2, O_CREAT, 0777, BUFFER_SIZE);
if (context.empty == SEM_FAILED)
{
fprintf(stderr, "%s\n", "ERROR creating semaphore semname2");
exit(EXIT_FAILURE);
}
context.buffer = buffer;
status = pthread_create(&reader, NULL, Reader, &context);
status = pthread_create(&writer, NULL, Writer, &context);
// pthread_join(reader,NULL); // This line seems to be necessary
// pthread_join(writer,NULL); // This line seems to be necessary
sem_unlink(context.semname1);
sem_unlink(context.semname2);
pthread_exit(NULL);
return 0;
}
pthread_join() is the standard way to wait for the other thread to complete, I would stick to that.
Alternatively, you can create a thread counter and have all child threads increment it by 1 at start, then decrement it by 1 when they finish (with proper locking of course), then have your main() wait for this counter to hit 0. (pthread_cond_wait() would be my choice).
Per normal pthread semantics, as taught e.g. here, your original idea does seem to be confirmed:
If main() finishes before the threads
it has created, and exits with
pthread_exit(), the other threads will
continue to execute. Otherwise, they
will be automatically terminated when
main() finishes.
However I'm not sure whether that's part of the POSIX threads standard or just a common but not universal "nice to have" add-on tidbit (I do know that some implementations don't respect this constraint -- I just don't know whether those implementations are nevertheless to be considered standard compliant!-). So I'll have to join the prudent chorus recommending the joining of every thread you need to terminate, just to be on the safe side -- or, as Jon Postel put it in the context of TCP/IP implementations:
Be conservative in what you send; be liberal in what you accept.
a "principle of robustness" that should be used way more broadly than just in TCP/IP;-).
pthread_exit(3) exits the thread that calls it (but not the whole process if other threads are still running). In your example other threads use variables on main's stack, thus when main's thread exits and its stack is destroyed they access unmapped memory, thus the segfault.
Use proper pthread_join(3) technique as suggested by others, or move shared variables into static storage.
When you pass a thread a pointer to a variable, you need to ensure that the lifetime of that variable is at least as long as the thread will attempt to access that variable. You pass the threads pointers to buffer and context, which are allocated on the stack inside main. As soon as main exits, those variables cease to exist. So you cannot exit from main until you confirm that those threads no longer need access to those pointers.
95% of the time, the fix for this problem is to follow this simple pattern:
1) Allocate an object to hold the parameters.
2) Fill in the object with the parameters.
3) Pass a pointer to the object to the new thread.
4) Allow the new thread to deallocate the object.
Sadly, this doesn't work well for objects shared by two or more threads. In that case, you can put a use count and a mutex inside the parameter object. Each thread can decrement the use count under protection of the mutex when it's done. The thread that drops the use count to zero frees the object.
You would need to do this for both buffer and context. Set the use count to 2 and then pass a pointer to this object to both threads.
pthread_join does the following :
The pthread_join() function suspends execution of the calling thread until the target thread terminates, unless the target thread has already terminated. On return from a successful pthread_join() call with a non-NULL value_ptr argument, the value passed to pthread_exit() by the terminating thread is made available in the location referenced by value_ptr. When a pthread_join() returns successfully, the target thread has been terminated. The results of multiple simultaneous calls to pthread_join() specifying the same target thread are undefined. If the thread calling pthread_join() is canceled, then the target thread will not be detached.
However you can achieve the same by using a light weight loop which will prevent the exe from exiting. In Glib this is achieved by creating a GMainLoop, in Gtk+ you can use the gtk_main.
After completion of threads you have to quit the main loop or call gtk_exit.
Alternatively you can create you own wait functionality using a combination of sockets,pipes and select system call but this is not required and can be considered as an exercise for practice.