How to use semaphores to control progress of 2 threads? - c

I learned the concept of semaphore. And I'm trying to implement it.
I've been trying to implement it for over 19 hours, but I can't do it, so I'm writing to ask for your help.
It checks the progress of the current two threads, just as it does with CV, and if both threads output entered, it can resume the subsequent operation.
Below is the full text of the code.
`
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
void *child1(void *arg) {
printf("child thread 1 entered!\n");
// call semaphoreshere here
printf("child thread 1 exits!\n");
return NULL;
}
void *child2(void *arg) {
printf("child thread 2: entered!\n");
// call semaphores here
printf("child thread 2: exits\n");
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t p1, p2;
printf("parent thread: begin\n");
// init semaphores here
// // sem_init(&empty, 0, 0);
// // sem_init(&full, 0, 0); //Code tried but not working properly
pthread_create(&p1, NULL, child1, NULL);
pthread_create(&p2, NULL, child2, NULL);
pthread_join(p1, NULL);
pthread_join(p2, NULL);
printf("parent thread: end\n");
return 0;
}
`
Using ONLY TWO semaphores within the code, this attempts to control the thread's internal execution order so that both threads must output the ~~entered message before it can exit.
The execution result I want is as follows.
>>>
parent thread: begin
child thread 1 entered!
child thread 2: entered!
child thread 2: exits
child thread 1 exits!
parent thread: end
>>>
parent thread: begin
child thread 2 entered!
child thread 1: entered!
child thread 1: exits
child thread 2 exits!
parent thread: end
Like this, I want to implement only the role of monitoring each other to see if they've entered.
I'd appreciate your help.
thanks.

What you want to do (in semaphoore-thinking) is:
thread 1 waits till thread 2 is done before it exits.
thread 2 waits till thread 1 is done before it exits.
Which leads to the following code, which I modified a bit because I cannot stand global variables.
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
typedef struct SharedContext_tag {
sem_t t1done;
sem_t t2done;
} SharedContext_t;
void *child1(void* arg) {
SharedContext_t* ctx = (SharedContext_t*) arg;
printf("child thread 1: entered!\n");
sem_post(&ctx->t1done);
sem_wait(&ctx->t2done);
printf("child thread 1 exits!\n");
return NULL;
}
void *child2(void* arg) {
SharedContext_t* ctx = (SharedContext_t*) arg;
printf("child thread 2: entered!\n");
sem_post(&ctx->t2done);
sem_wait(&ctx->t1done);
printf("child thread 2: exits!\n");
return NULL;
}
int main(int argc, const char* argv[]) {
pthread_t p1;
pthread_t p2;
SharedContext_t context;
sem_init(&context.t1done, 0, 0);
sem_init(&context.t2done, 0, 0);
printf("parent thread: begin\n");
pthread_create(&p1, NULL, child1, &context);
pthread_create(&p2, NULL, child2, &context);
pthread_join(p1, NULL);
pthread_join(p2, NULL);
printf("parent thread: end\n");
sem_close(&context.t1done);
sem_close(&context.t2done);
return 0;
}
On my machine at this time (being careful here!), the output is as required:
> ./sema
parent thread: begin
child thread 1: entered!
child thread 2: entered!
child thread 2: exits!
child thread 1 exits!
parent thread: end
In order for it to work, you need to link against the real-time library, librt. You do so by adding -pthread to your compile command.
> clang-13 -g -O0 -pthread -o sema sema.c

Related

Issue with muilti-threading with pthread: thread is executing prematurely

I am trying to call make a thread to another function in a function being ran by a child process. I am starting by calling a child process, which makes another child process, which in turn makes a thread. However, the thread function keeps executing prematurely. What could be the issue?
#define _GNU_SOURCE
#include <sched.h>
#include <pthread.h> // pthread
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>// waitpid
#include <sys/wait.h> //waitpid
#define STACK_Size 1024*1024
void* print(void* ptr)
{
printf("\n4. In thread\n");
char* message;
message = (char*)ptr;
printf("\n5. Message from parent: %s \n\n",message);
}
static int threading(void * ptr)
{
char* message;
message = (char*)ptr;
printf("\n3. In child process 2\n");
pthread_t Tid;
pthread_create(&Tid,NULL,&print,(void*)message);
pthread_join(Tid,NULL);
printf("\n6. Thread done.... exiting child process 2\n\n");
}
static int child(void *ptr)
{
char* message;
message = (char*) ptr;
print("\n2. In child 1");
// creating child process
char* stack_ptr = malloc(STACK_Size);
unsigned long flags =0;
pid_t pid;
pid = clone(threading, stack_ptr+STACK_Size,flags | SIGCHLD,message);
int status;
waitpid(pid,&status,0);
printf("7. Done with child 2\n\n8. Now exiting child process 1\n");
}
int main(int argc, char ** argv)
{
char msg[150];
printf("1. Currently in main program name: %s\n", argv[0]);
sprintf(msg,"The name of the program is (%s), P.S this is parent (pid:%d)",argv[0],getpid());
char* stack_pointer = malloc(STACK_Size);
unsigned long flags =0;
setbuf(stdout,NULL);
if((argc >1) && (strcmp(argv[1],"vm")==0))
{
flags = CLONE_VM;
}
pid_t pid;
pid = clone(child,stack_pointer+STACK_Size,flags | SIGCHLD,msg);
int status;
waitpid(pid,&status,0);
printf("\n9. Done with Parent process\n");
}
Here is the output it's producing:
1. Currently in main program name: ./clone
4. In thread
5. Message from parent:
2. In child 1
3. In child process 2
4. In thread
5. Message from parent: The name of the program is (./clone), P.S this is parent (pid:15159)
6. Thread done.... exiting child process 2
7. Done with child 2
8. Now exiting child process 1
9. Done with Parent process
If what you mean by executing prematurely is the lines containing 4. and 5. being printed before 2., it's because you call your custom print() function to output 2. (print("\n2. In child 1")) which also prints out 4. and 5..

How to join a thread which have fork in it?

Following is the case.
{
...
pthread_create(thread_id, NULL, thread_fun, NULL);
pthread_join(thread_id, NULL);
...
}
void * thread_fun(void * arg)
{
if(fork())
{
printf("In Parent\n");
pthread_exit(NULL);
}
else
{
printf("In Child\n");
pthread_exit(NULL);
}
}
How to use pthread_join() in such a way that I can wait for both child and parent process in thread?
Put all threads into endless loops and then inspect the whole program state with ps, top, htop or similar tools. You will find that the child process only has a single thread, while the parent process has (at least) two.
Now, concerning your question how to use pthread_join() to wait for the child process, you simply can't, because you can only use it to wait for threads in the same process. You could wait for the child process to terminate (waitpid()).
If the above doesn't answer your question (it's a bit unclear because you want to "wait for both child and parent process", which is where I wonder from which process' context) take a step back instead and describe on a higher level what you're trying to achieve instead. In other words, this could be a so-called "XY Problem". Do a bit of research on that term, it's a good thing to learn and understand in any case.
There's basically two ways you can do it. You can either have the child thread wait for the child process before it exits, or you can pass the PID of the child process to the parent thread so it can wait for it. Here's the first approach:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
void *thread_fun(void *arg);
int main(void) {
pthread_t thread;
pthread_create(&thread, NULL, thread_fun, NULL);
pthread_join(thread, NULL);
return 0;
}
void *thread_fun(void *arg) {
pid_t pid = fork();
if(pid) {
printf("In Parent\n");
waitpid(pid, NULL, 0);
pthread_exit(NULL);
} else {
printf("In Child\n");
exit(0);
}
}
And here's the second:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
struct locked_pid {
sem_t sem;
pid_t pid;
};
void *thread_fun(void *arg);
int main(void) {
pthread_t thread;
struct locked_pid s;
sem_init(&s.sem, 0, 0);
pthread_create(&thread, NULL, thread_fun, &s);
sem_wait(&s.sem);
waitpid(s.pid, NULL, 0);
pthread_join(thread, NULL);
sem_destroy(&s.sem);
return 0;
}
void *thread_fun(void *arg) {
pid_t pid = fork();
if(pid) {
struct locked_pid *s = arg;
s->pid = pid;
sem_post(&s->sem);
printf("In Parent\n");
pthread_exit(NULL);
} else {
printf("In Child\n");
exit(0);
}
}
Note that the first is much simpler than the second. This is because in the second, you need a semaphore so that the parent process knows when the child PID gets written.
By the way, there's two things you should know about this code before you use it in anything important:
It doesn't have any error-checking, even though most of the functions it uses can fail.
POSIX says "If a multi-threaded process calls fork() ... the child process may only execute async-signal-safe operations until such time as one of the exec functions is called." This means that you shouldn't be doing printf("In Child\n");.

Multithreading Producer and Consumer with Semaphores in C

I am having issues getting my project to work and was hoping someone could assist. The guidelines are as follows:
You will use the
pthread package to create 4 producer threads and 4 consumer threads. Each producer thread inserts
character ‘X’ into a buffer of size 10,000,000 characters. Each consumer thread removes the most recently-inserted
character from the buffer. Each thread then repeats the process
So far my code looks like this:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <pthread.h>
#define N 10000000
sem_t mutex;
sem_t full;
sem_t empty;
typedef struct
{
char const* buf[N];
char in;
char out;
} bufferItems;
bufferItems sharedBuffer;
void *producer(void *arg) {
while(1) {
sem_wait(&empty);
sem_wait(&mutex);
sharedBuffer.buf[sharedBuffer.in] = "X";
sharedBuffer.in = (sharedBuffer.in+1)%N;
printf("Producer\n");
sem_post(&mutex);
sem_post(&full);
}
}
void *consumer(void *arg){
while(1){
sem_wait(&full);
sem_wait(&mutex);
sharedBuffer.buf[sharedBuffer.out] = NULL;
sharedBuffer.out = (sharedBuffer.out+1)%N;
printf("Consumer\n");
sem_post(&mutex);
sem_post(&empty);
}
}
int main(void) {
sem_init(&mutex, 0, 0);
sem_init(&full, 0, 0);
sem_init(&empty, 0, N);
pthread_t p;
pthread_t c;
// create four producer threads
for(int t=0; t<4; t++){
printf("In main: creating producer thread %d\n", t);
int err = pthread_create(&p,NULL,producer,NULL);
if (err){
printf("ERROR from pthread_create() on producer thread %d\n", err);
exit(-1);
}
}
// create four consumer threads
for(int t=0; t<4; t++){
printf("In main: creating consumer thread %d\n", t);
int err = pthread_create(&c,NULL,consumer,NULL);
if (err){
printf("ERROR; from pthread_create() on consumer thread %d\n", err);
exit(-1);
}
}
}
But the output I get when I run it is this:
In main: creating producer thread 0
In main: creating producer thread 1
In main: creating producer thread 2
In main: creating producer thread 3
In main: creating consumer thread 0
In main: creating consumer thread 1
In main: creating consumer thread 2
In main: creating consumer thread 3
It seems as though the child threads are either not executing, or the semaphores are not working properly so there is deadlock. Any recommendation on how to make my code better or work properly would be greatly appreciated.
You need to call pthread_join in your main thread after creating all the child threads. pthread_join waits for the specified thread to terminate. Otherwise the main thread will exit and take out all the child threads prematurely.

Pthread in C basic print

I'm writing a C program using Pthreads that creates a child thread. After creating the child thread, the parent thread should ouput two messages: "parent:begin" then it should print "parent:done". Same for child thread "child:begin" and "child:done". I have to make sure that the main thread prints his second message before the spawned (child) thread does. I have to following implementation but it only prints in the wrong order. I assume I should use flags. Any help would be appreciated.
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
volatile int done = 0;
void *child(void *arg) {
printf("child\n");
done = 1;
printf("child:done");
return NULL;
}
int main(int argc, char *argv[]) {
printf("parent: begin\n");
pthread_t c;
pthread_create(&c, NULL, child, NULL); // create child
while (done == 0); // spin
printf("parent: end\n");
return 0;
}
If you want the parent to print done first, then you should have the child thread spin until the parent is done. (Right now the parent spins waiting for the child.) You should also use pthread_join to make sure the child is done before the main thread returns:
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
volatile int done = 0;
void *child(void *arg) {
printf("child: begin\n");
while (done == 0); // spin
printf("child: done\n");
return NULL;
}
int main(int argc, char *argv[]) {
printf("parent: begin\n");
pthread_t c;
pthread_create(&c, NULL, child, NULL); // create child
printf("parent: done\n");
done = 1;
pthread_join(c, NULL);
return 0;
}
On my machine I get this output:
parent: begin
parent: done
child: begin
child: done
At the moment done is accessed without any synchronization by both threads. Proper way is to signal the child that the parent has completed printing using a conditional variable. This leads to data race.
Moreover, main() thread complete the execution before the does. In that case, the whole process will die. You can either call pthread_join() or simply exit the main thread with pthread_exit().
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
volatile int done = 0;
void *child(void *arg) {
printf("child\n");
pthread_mutex_lock(&mutex);
while(done == 0)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
printf("child:done");
return NULL;
}
int main(int argc, char *argv[]) {
printf("parent: begin\n");
pthread_t c;
pthread_create(&c, NULL, child, NULL); // create child
pthread_mutex_lock(&mutex);
done = 1;
printf("parent: end\n");
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
pthread_exit(0);
}

Detached thread won't exit although it runs pthread_exit?

I have been dealing with a problem in a thread pool for some days now. I tried all types of different things but I can't seem to solve the issue. I have made a simple version that reproduces the problem.
Code:
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
struct bsem_t bsem;
pthread_t threads[2];
/* Binary semaphore */
typedef struct bsem_t {
pthread_mutex_t mutex;
pthread_cond_t cond;
int v;
} bsem_t;
void bsem_post(bsem_t *bsem) {
pthread_mutex_lock(&bsem->mutex);
bsem->v = 1;
pthread_cond_broadcast(&bsem->cond);
pthread_mutex_unlock(&bsem->mutex);
}
void bsem_wait(bsem_t *bsem) {
pthread_mutex_lock(&bsem->mutex);
while (bsem->v != 1) {
pthread_cond_wait(&bsem->cond, &bsem->mutex);
}
bsem->v = 0;
pthread_mutex_unlock(&bsem->mutex);
}
/* Being called by each thread on SIGUSR1 */
void thread_exit(){
printf("%u: pthread_exit()\n", (int)pthread_self());
pthread_exit(NULL);
}
/* Startpoint for each thread */
void thread_do(){
struct sigaction act;
act.sa_handler = thread_exit;
sigaction(SIGUSR1, &act, NULL);
while(1){
bsem_wait(&bsem); // Each thread is blocked here
puts("Passed semaphore");
}
}
/* Main */
int main(){
bsem.v = 0;
pthread_create(&threads[0], NULL, (void *)thread_do, NULL);
pthread_create(&threads[1], NULL, (void *)thread_do, NULL);
pthread_detach(threads[0]);
pthread_detach(threads[1]);
puts("Created threads");
sleep(2);
pthread_kill(threads[0], SIGUSR1);
pthread_kill(threads[1], SIGUSR1);
puts("Killed threads");
sleep(10);
return 0;
}
What the code does, is create two threads. Both threads wait on a binary semaphore (bsem_wait). Then while they are waiting I send a SIGUSR1 signal to both resulting on pthread_exit() being executed on each thread. On my terminal it shows that everything goes as planned..
Output:
Created threads
Killed threads
2695145216: pthread_exit()
2686752512: pthread_exit()
The problem
Although the output seems correct, using pstree shows that only one of two threads die. The other thread stays alive until the whole program exits. Why is this?
Update
Replacing my custom binary semaphore with a normal semaphore seems to solve this for no apparent reason..
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
#include <semaphore.h>
sem_t sem;
pthread_t threads[2];
/* Caller thread will exit */
void thread_exit(){
printf("%u: pthread_exit()\n", (int)pthread_self());
pthread_exit(NULL);
}
/* Startpoint for each thread */
void* thread_do(){
struct sigaction act;
act.sa_handler = thread_exit;
sigaction(SIGUSR1, &act, NULL);
while(1){
sem_wait(&sem); // Each thread is blocked here
puts("Passed semaphore");
}
}
/* Main */
int main(){
sem_init(&sem, 0, 0); // Normal semaphore
pthread_create(&threads[0], NULL, thread_do, NULL);
pthread_create(&threads[1], NULL, thread_do, NULL);
pthread_detach(threads[0]);
pthread_detach(threads[1]);
puts("Created threads in pool");
sleep(2);
//PROBLEM
pthread_kill(threads[0], SIGUSR1);
pthread_kill(threads[1], SIGUSR1);
puts("Destroyed pool");
sleep(10);
return 0;
}
You can't get there from here
pthread_exit() is not listed in the "signal safe funtions" of the signal(7) man page.
rewrite your code to have the pthread_exit call outside of the signal handler.
So the issue seemed to be a deadlock!
The problem is that each thread is waiting inside the bsem_wait of the binary semaphore in different locations:
void bsem_wait(bsem_t *bsem) {
pthread_mutex_lock(&bsem->mutex); // THREAD 2 BLOCKED HERE
while (bsem->v != 1) {
pthread_cond_wait(&bsem->cond, &bsem->mutex); // THREAD 1 WAITING HERE
}
bsem->v = 0;
pthread_mutex_unlock(&bsem->mutex);
}
Thread 1 in this case is the fastest thread. Thread 2 is the slower one. When I run the signal to kill a thread, the waiting thread unblocks and exits as expected. The problem is that it never unlocks the mutex. So the blocked thread (2) remains blocked forever. For some reason, the thread won't be terminated because it is waiting on the mutex.
Just adding an unblock before exiting, solves the issue:
void thread_exit(){
printf("%u: pthread_exit()\n", (int)pthread_self());
pthread_mutex_unlock(&mutex); // NEW CODE
pthread_exit(NULL);
}
This ofcourse is a hack to demonstrate what is happening and shouldn't be used. I am going to follow Jasen's advice and get rid of the signal handler all together and solve it some other way. Namely I have to assure that the thread goes through the whole bsem_wait!

Resources