I have a project about marriage operations. In this program, a thread called registrar uses marriage function. In this marriage operations, we have brides and grooms. Marriage function does decrease bride count and groom count one by one. But i have a problem while i want to decrease these count.
MAIN.c
#include<pthread.h>
#include<stdlib.h>
#include<stdio.h>
#include<semaphore.h>
#include "bride.h"
#include "groom.h"
pthread_t groomThread;
pthread_t brideThread;
sem_t registrarSemaphore;
pthread_mutex_t lock;
int *groomCount = 14;
int *brideCount = 20;
int *availableRegistrar;
void createBride(int *brideCount) {
pthread_create(&brideThread, NULL, &increaseBrideCount, (void *) brideCount);
}
void createGroom(int *groomCount) {
pthread_create(&groomThread, NULL, &increaseGroomCount, (void *) groomCount);
}
void deleteGroom(int *groomCount) {
pthread_create(&groomThread, NULL, &decreaseGroomCount, (void *) groomCount);
}
void deleteBride(int *brideCount) {
pthread_create(&brideThread, NULL, &decreaseBrideCount, (void *) brideCount);
}
void marriage() {
sem_init(®istrarSemaphore, 0, 2);
while (1) {
sem_getvalue(®istrarSemaphore, &availableRegistrar);
printf("\nAvailable Registrar Number = %d\n", availableRegistrar);
printf("bride %d\n", brideCount);
printf("groom %d\n", groomCount);
if (brideCount > 0 && groomCount > 0) {
sem_wait(®istrarSemaphore);
sem_getvalue(®istrarSemaphore, &availableRegistrar);
printf("Available Registrar %d \n", availableRegistrar);
printf("Marriage Bride %d and Groom %d \n", brideCount, groomCount);
pthread_mutex_lock(&lock);
deleteBride(brideCount);
pthread_mutex_unlock(&lock);
//pthread_join(brideThread, &brideCount);
pthread_mutex_lock(&lock);
deleteGroom(groomCount);
pthread_mutex_unlock(&lock);
//pthread_join(groomThread, &groomCount);
printf("Exiting critical region...\n\n");
/* END CRITICAL REGION */
sem_post(®istrarSemaphore);
}
int random = rand() % 100;
if (random % 7 > 4) {
printf("Bride Created\n");
pthread_mutex_lock(&lock);
createBride(brideCount);
//pthread_join(brideThread, &brideCount);
pthread_mutex_unlock(&lock);
}
if (random % 7 < 2) {
printf("Groom Created\n");
pthread_mutex_lock(&lock);
createGroom(groomCount);
//pthread_join(groomThread, &groomCount);
pthread_mutex_unlock(&lock);
}
pthread_join(brideThread, &brideCount);
pthread_join(groomThread, &groomCount);
for (int i = 0; i < 100000000; i++);
printf("------------------------------");
}
}
int main(void) {
marriage();
}
In pthread_create part, there are some functions as you can see. It defined in .h part. For example in bride.h, there are 2 functions about bride.
BRIDE.H
#ifndef BRIDE_H
#define BRIDE_H
void* increaseBrideCount(void * bride);
void* decreaseBrideCount(void * bride);
#endif
BRIDE.C
#include <pthread.h>
#include "bride.h"
void* increaseBrideCount(void *bride){
int brideCount = (int)bride;
brideCount++;
pthread_exit(brideCount);
}
void* decreaseBrideCount(void* bride){
int brideCount = (int)bride;
brideCount--;
pthread_exit(brideCount);
}
While im creating new bride,i cant send the new value of bride to the function. For example :
I have 20 brides and 14 grooms at first.
I have 2 available registrar
Marraige does.
Bride count = 19, groom count = 13
Then, i want to create new bride.
It count goes to = 1 :( Im trying to make it 20 again.
If you can help, i would be very happy. Thank you
Semaphores are used to make sure only one of the threads that might make a particular change does so at a time. The things being changed in this case are the bride and groom counts, so you need to "protect" them using semaphores. You even seem to have created semaphores for this purpose (brideSemaphore and groomSemaphore); you just need to use them.
By the way: if you use a semaphore only in a single thread, you're wasting your time (as seems to be the case w/ your registrarSemaphore) in marriage()). Either it needs to be used elsewhere as well, or not at all.
Related
I am making a raytracer, im trying to use pthread to divide the rendering. i noticed that isnt helping with the speed because the function pthread_join is to slow, if i use a loop to make the 'await' is way faster and works almost every time fine. But i cant use that because the time of rendering changes with the scene.
Is there a way to check if a thread is finished, on a more efficient way. This is the code.
`
int threats(t_file *c) //this function creates the threads
{
int i;
int err;
pthread_t th[THREADS];
i = 0;
printf("1\n");
c->thread = -1;
mlx_clear_window(c->mlx_ptr, c->win_ptr);
while (i < THREADS)
{
err = pthread_create(&th[i], 0, (void *)paint_scene, (void *)c);
if (err)
return parse_error("Thread Error: CAN NOT CREATE THREAD");
i++;
}
// while (i-- >= 0)
// pthread_join(th[i], 0);
//my await function xd
while (i < 200000000)
i++;
mlx_put_image_to_window(c->mlx_ptr, c->win_ptr, c->img.mlx_img, 0, 0);
c->thread = 0;
return 1;
}
void paint_scene(void *a)
{
int y;
int x;
t_ray ray;
int color;
t_file *c;
c = (t_file *)a;
color = 0;
c->thread++;
y = (c->thread * (c->win_heigth / THREADS));
printf("y:%d,hilo%d\n", y, c->thread);
while (y < (c->thread + 1) * (c->win_heigth / THREADS))
{
x = 0;
while (x < c->win_width)
{
ray = generate_ray(x, y, *c);
color = get_intersections(&ray, c);
if (c->ligth)
color = shading(&ray, color, c);
my_mlx_pixel_put(&c->img, x, y, color);
x++;
}
//ft_printf("\rLoading%d: %d%%", c->thread, y / (c->win_heigth / 100));
y++;
}
pthread_exit(0);
}
`
You have a concurrency problem here in your thread function:
c->thread++;
y = (c->thread * (c->win_heigth / THREADS));
printf("y:%d,hilo%d\n", y, c->thread);
while (y < (c->thread + 1) * (c->win_heigth / THREADS))
{
....
}
c->thread is shared between all threads, and based on likely thread timings and current face of the moon, I can make an educated guess and say that the first thread is calculating the whole image. When starting up, the first thread might see c->thread == -1, but later (if thread startup is faster than the while loop) other thread increase the value until the first thread sees c->thread == THREADS-1
To fix this, each call to create_thread must pass a pointer to a unique parameter object that holds that threads id. So remove the thread member from t_file. It probably serves no purpose there. And create a type of struct that holds the parameters to the thread function:
struct thread_param
{
unsigned int thread;
file_t *c;
}
You use it like this when starting threads:
struct thread_param params[THREADS];
while (i < THREADS)
{
params[i].thread = i;
params[i].c = c;
err = pthread_create(&th[i], 0, (void *)paint_scene, (void *)&(params[i]));
if (err)
return parse_error("Thread Error: CAN NOT CREATE THREAD");
i++;
}
And you access the data in your thread function:
void paint_scene(void *a)
{
struct thread_param *param = (struct thread_param *)a;
unsigned int thread = param->thread;
t_file *c = param->c;
/*
in the rest of the code you remove `c->thread++`
and replace `c->thread` with `thread`
*/
....
}
If you have atomic data types (C11, #ifndef __STDC_NO_ATOMICS__) then implement a global counter and wait until it hits zero (if decreasing) or the amount of threads (if increasing).
e.g.
#include <stdatomic.h>
atomic_int num_jobs;
void* thread_func(void*)
{
//the work to do in the thread function
//before exit decrease counter
--num_jobs;
pthread_exit(0);
}
int main()
{
num_jobs = THREADS; // same as your number of threads
create_threads(THREADS); // number of threads = THREADS
while (num_jobs) { // loop while threads running
//sleep for a while
}
join_threads(); // join threads for cleanup
return 0;
}
Otherwise classic lock mechanics,
e.g.
#include <pthread.h>
pthread_spinlock_t lock;
int num_jobs;
// called by main
int numJobs()
{
pthread_spin_lock(&lock);
int res = num_jobs;
pthread_spin_unlock(&lock);
return res;
}
// called by thread_func
void decNumJobs()
{
pthread_spin_lock(&lock);
--num_jobs;
pthread_spin_unlock(&lock);
}
int main()
{
pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
// the other stuff as before
pthread_spin_destroy(&lock);
return 0;
}
Another alternative would be with pthread_cond_wait and pthread_cond_signal (mainly to avoid the sleep in the while loop, continue after receiving the signal and not based on a fixed amount of time).
e.g.
#include <pthread.h>
int num_jobs;
pthread_cond_t cond;
pthread_mutex_t lock;
void decNumJobs()
{
pthread_mutex_lock(&lock);
if (--num_jobs == 0)
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
void* thread_func(void*)
{
//the work to do in the thread function
//before exit decrease counter
decNumJobs();
pthread_exit(0);
}
int main()
{
num_jobs = THREADS;
pthread_cond_init(&cond, NULL);
pthread_mutex_init(&lock, NULL);
pthread_mutex_lock(&lock);
create_threads(THREADS);
pthread_cond_wait(&cond, &lock);
pthread_mutex_unlock(&lock);
join_threads();
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&lock);
return 0;
}
Note: For the sake of simplicity, there is no error checking nor handling. Reading the documentation of the pthread_* functions (return values, interrupted wait, etc) is strongly advised.
We have to make a program that simulates the function of a booking system for seats in a theater. We have N_cust clients that call at the telephone center and N_tel people who answer the phone calls. Each call lasts from t_seathigh to t_seatlow seconds. The payment with the credit card is successful with probability P_cardsuccess. The two arguments that the program gets are the number of clients and the seed for rand_r.There is a thread for each client, and the clients have to wait for a person to talk on the phone. My problem is that the program runs but gives a segmentation fault or gets stuck in an infinite loop on the first loop of the function AwesomeThreadFunction.
I thought that maybe I have not handled the variable telefoners correctly since the program sometimes gets stuck in the first loop of the function but I don't know how exactly. I also don't know why I get this segmentation fault. Where exactly does my program try to access not allocated memory.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include "p3170013-p3170115-p3170097-res1.h"
#include <unistd.h>
#define N_seat 250
#define N_tel 8
#define N_seatlow 1
#define N_seathigh 5
#define t_seatlow 5
#define t_seathigh 10
#define P_cardsuccess 0.9
#define C_seat 20.0
#define BILLION 1E9
pthread_mutex_t lock_phone, lock_bank_account,lock_number_of_transfer,lock_wait_time, lock_service_time, lock_plan, lock_screen;
int plan[N_seat];
int phone_count=0,bank_account=0,tid=0,seats=0,telefoners=N_tel;
unsigned int seed;
float avg_wait_time=0,avg_service_time;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* AwesomeThreadFunction(void* vargc){
tid=*(int*)vargc;
struct timespec waitStart, waitEnd;
clock_gettime(CLOCK_REALTIME, &waitStart);
avg_wait_time-=(waitStart.tv_sec+waitStart.tv_nsec/BILLION);
pthread_mutex_lock(&lock_screen);
printf("%d\n",telefoners);
pthread_mutex_unlock(&lock_screen);
pthread_mutex_lock(&lock_phone);
while (telefoners == 0) {
pthread_cond_wait(&cond, &lock_phone);
}
telefoners--;
pthread_mutex_unlock(&lock_phone);
pthread_mutex_lock(&lock_screen);
printf("coooooooool\n");
pthread_mutex_unlock(&lock_screen);
clock_gettime(CLOCK_REALTIME, &waitEnd);
avg_wait_time+=(waitEnd.tv_sec+waitEnd.tv_nsec/BILLION);
struct timespec talkStart, talkEnd;
clock_gettime(CLOCK_REALTIME, &talkStart);
int how_many_seats=rand_r(&seed);
seed=how_many_seats;
how_many_seats=how_many_seats%(N_seathigh-N_seatlow)+N_seatlow;
int how_many_seconds=rand_r(&seed);
seed=how_many_seconds;
how_many_seconds=how_many_seconds%(t_seathigh-t_seatlow)+t_seatlow;
sleep(how_many_seconds);
if(seats==N_seat){
pthread_mutex_lock(&lock_screen);
printf("%d Reservation cancelled because the theater is full\n",*(int*)vargc);
pthread_mutex_unlock(&lock_screen);
}else if(seats+how_many_seats>N_seat){
pthread_mutex_lock(&lock_screen);
printf("%d Reservation cancelled because there are not enough seats available\n",*(int*)vargc);
pthread_mutex_unlock(&lock_screen);
}else{
int c=0,i=0;
pthread_mutex_lock(&lock_number_of_transfer);
pthread_mutex_unlock(&lock_number_of_transfer);
pthread_mutex_lock(&lock_plan);
while(c<how_many_seats){
if(!plan[i]){
plan[i]=tid;
c++;
}
i++;
}
seats+=how_many_seats;
pthread_mutex_unlock(&lock_plan);
int card_success=rand_r(&seed);
seed=card_success;
float tempp=(float)card_success/(float)RAND_MAX;
card_success=(tempp<=P_cardsuccess);
if(!card_success){
pthread_mutex_lock(&lock_screen);
printf("%d Reservation cancelled because the transaction with the credit card was not accepted\n",*(int*)vargc);
pthread_mutex_unlock(&lock_screen);
pthread_mutex_lock(&lock_plan);
c=0;i=0;
while(c<how_many_seats){
if(plan[i]==tid){
plan[i]=0;
c++;
}
pthread_mutex_lock(&lock_screen);
pthread_mutex_unlock(&lock_screen);
i++;
}
seats-=how_many_seats;
pthread_mutex_unlock(&lock_plan);
pthread_mutex_lock(&lock_number_of_transfer);
pthread_mutex_unlock(&lock_number_of_transfer);
}else{
pthread_mutex_lock(&lock_screen);
printf("%d Reservation completed successfully.The number of the transaction is %d, your seats are ",*(int*)vargc,*(int*)vargc);
pthread_mutex_unlock(&lock_screen);
c=0;i=0;
pthread_mutex_lock(&lock_plan);
while(c<how_many_seats){
if(plan[i]==*(int*)vargc){
pthread_mutex_lock(&lock_screen);
printf("%d ",i);
pthread_mutex_unlock(&lock_screen);
c++;
}
i++;
}
pthread_mutex_unlock(&lock_plan);
pthread_mutex_lock(&lock_screen);
printf("and the cost of the transaction is %.2f euros\n",how_many_seats*C_seat);
pthread_mutex_unlock(&lock_screen);
pthread_mutex_lock(&lock_bank_account);
bank_account+=how_many_seats*C_seat;
pthread_mutex_unlock(&lock_bank_account);
}
}
//we assume that the client is fully served when we have also printed out his/her result of the try to book seats
clock_gettime(CLOCK_REALTIME, &talkEnd);
double cow = ( talkEnd.tv_sec - talkStart.tv_sec ) + ( talkEnd.tv_nsec - talkStart.tv_nsec ) / BILLION;
pthread_mutex_lock(&lock_service_time);
avg_service_time+=cow;
pthread_mutex_unlock(&lock_service_time);
pthread_mutex_lock(&lock_phone);
telefoners++;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock_phone);
pthread_exit(0);
}
int main(int argc,char* argv[]){
int i;
for(i=0;i<N_seat;i++){
plan[i] = 0;
}
//if user did not give the correct number of arguments
if(argc!=3){
printf("Wrong number of arguments\n");
return -1;
}
int N_cust=atoi(argv[1]),tel_available=N_tel,err;
i=0;
seed=atoi(argv[2]);
pthread_t *threads=(pthread_t*)malloc(N_cust*sizeof(pthread_t));
int threadid[N_cust];
//if we can't init one of the mutexes
pthread_mutex_init(&lock_phone, NULL);
pthread_mutex_init(&lock_bank_account, NULL);
pthread_mutex_init(&lock_number_of_transfer, NULL);
pthread_mutex_init(&lock_wait_time, NULL);
pthread_mutex_init(&lock_service_time, NULL);
pthread_mutex_init(&lock_plan, NULL);
pthread_mutex_init(&lock_screen, NULL);
//creating the threads
while(i<N_cust){
threadid[i]=i+1;
err = pthread_create(&(threads[i]), NULL, AwesomeThreadFunction, (void*)&threadid[i]); //func name
if (err){
printf("Thread can't be created :[%s]\n", strerror(err));
}
i++;
}
//join the threads
void *status;
for (i = 0; i < N_cust; i++) {
rc = pthread_join(threads[i], &status);
if (rc != 0) {
printf("ERROR: return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main: Thread %lu finished with status %d.\n", threads[i], *(int *)status);
}
//final output
for(i=0;i<N_seat;++i){
if(plan[i]){
printf("Seat %d / client %d\n",i+1,plan[i]);
}
}
printf("Total revenue from sales:\t%d\n",bank_account);
printf("Average waiting time:\t%f\n",(float)avg_wait_time/(float)N_cust);
printf("Average service time:\t%f\n",(float)avg_service_time/(float)N_cust);
free(threads);
//Destroy mutexes
pthread_mutex_destroy(&lock_phone);
pthread_mutex_destroy(&lock_bank_account);
pthread_mutex_destroy(&lock_number_of_transfer);
pthread_mutex_destroy(&lock_wait_time);
pthread_mutex_destroy(&lock_service_time);
pthread_mutex_destroy(&lock_plan);
pthread_mutex_destroy(&lock_screen);
pthread_cond_destroy(&cond);
return 0;
}
An immediate problem leading to segfault is in (irrelevant details omitted):
if(seats+how_many_seats>N_seat) {
....
} else {
int c=0,i=0;
pthread_mutex_lock(&lock_plan);
while(c<how_many_seats) {
if(!plan[i]){
plan[i]=tid;
c++;
}
i++;
}
seats+=how_many_seats;
pthread_mutex_unlock(&lock_plan);
The code determines if it can satisfy the request, and happily proceeds to reserving seats. Only then it locks the plan. Meanwhile, between testing for seats+how_many_seats>N_seat and locking the plan, another thread does the same and modifies the plan. After that there is less seats available than the first thread expects, and the while(c<how_many_seats) loop accesses plan off bounds.
I didn't check the rest; I expect other similar problems. The non-volatile globals are very suspicious. In any case, do yourself a favor and use more functions.
I'm doing some university tasks and I managed to change the code and achieve the task properly but the console bugs out and acts strange.
The image can be found here since I don't have 10 reputation yet
https://imgur.com/a/X7a6bpa
You have the linux Ubuntu LED console and you can toggle the white and red lights as well as increase or decrease the speed at which they flash between a max and min amount.
The task was to have the console write out the current state of leds and the delay at which they flash.
Now I made that but due to interference, wrong semaphore usage or some code errors the console starts having random numbers appear in different parts of it. I've searched and couldn't find any reason for it. I'm also not sure what I'm actually looking at so an answer might already exist.
This is running Ubuntu 16.04.6 Xebian as that's what the uni requires. It includes threads and semaphores. I tried changing the semaphores and code around but it didn't work. I'm also fairly new to threads and semaphores so they might be completely in the wrong places.
I added as little code as possible. The things I wrote are the *led_info_thr function and creation in main,the semaphore in *led_toggle_thr.
static bool flashing[2] = {false, false};
static int flashing_delay[2] = {FLASH_INITIAL_DELAY, FLASH_INITIAL_DELAY};
static sem_t mutex;
void *led_toggle_thr(void *arg);
void *keyboard_thr(void *arg);
void *led_info_thr(void *arg);
void inc_delay(int i);
void dec_delay(int i);
int main (void) {
pthread_t thread[4];
int rc;
unsigned long i;
sem_init(&mutex,0 ,1);
console_init();
for (i = 0; i < 3; i += 1) {
rc = pthread_create(&thread[i], NULL, led_toggle_thr, (void *)i);
assert(rc == 0);
}
rc = pthread_create(&thread[2], NULL, keyboard_thr, NULL);
assert(rc == 0);
rc = pthread_create(&thread[3], NULL, led_info_thr, NULL);
assert(rc == 0);
while (true) {
/* skip */
}
exit(0);
}
void *led_toggle_thr(void *arg) {
unsigned long id = (long)arg;
while (true) {
if (flashing[id]) {F
sem_wait(&mutex);
led_toggle((leds_t)id);
sem_post(&mutex);
}
usleep(flashing_delay[id]);
}
}
void *led_info_thr(void *arg) {
char flashing_str[2]={'N','N'};
while(true)
{
for(int i = 0; i < 2; i++)
{
if(flashing[i] == true) flashing_str[i] = 'Y';
else flashing_str[i] = 'N';
sem_wait(&mutex);
lcd_write_at(i, 0, "LED%d F:%c D:%d", i, flashing_str[i], flashing_delay[i]);
sem_post(&mutex);
}
}
return NULL;
}
`
I got stuck when I was trying to print the summary of all threads (namely, grand totals of a group of threads).
The C code below runs 10 threads, simulating agents that sell tickets. After running & completing the threads (i.e. after all the tickets are sold), I want to print the list of agents and corresponding number of tickets sold by that agent. However, the main process terminates as soon as it hits the line pthread_exit(NULL) (marked with a preceding comment) and the code does not return to main, where it is supposed to print the grand totals (this block is marked with a comment as well).
Can anyone tell what's wrong with the code?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
struct ThreadArgs {
int thNum;
int *numTickets;
int *soldTickets;
sem_t *lock;
};
void *SellTickets(void *th) {
struct ThreadArgs *thArgs;
int sleepTime;
thArgs = th;
while (1) {
sleepTime = rand();
if (sleepTime % 2) {
usleep(sleepTime % 1000000);
}
sem_wait(thArgs->lock);
if (*thArgs->numTickets == 0) {
break;
}
printf("There are %3d ticket(s). Agent %d sold a ticket.\n", *thArgs->numTickets, thArgs->thNum);
(*thArgs->numTickets)--;
sem_post(thArgs->lock);
(*thArgs->soldTickets)++;
}
sem_post(thArgs->lock);
pthread_exit(NULL);
}
void runThreads(int numAgents, int numTickets, int soldTickets[]) {
struct ThreadArgs thArgs[numAgents];
int agent;
pthread_t th[numAgents];
sem_t lock;
sem_init(&lock, 1, 1);
for (agent = 0; agent < numAgents; agent++) {
thArgs[agent].thNum = agent;
thArgs[agent].soldTickets = &soldTickets[agent];
thArgs[agent].numTickets = &numTickets;
thArgs[agent].lock = &lock;
pthread_create(&th[agent], NULL, SellTickets, &thArgs[agent]);
}
// when debugging, the process terminates here
pthread_exit(NULL);
}
int main() {
int agent, numAgents, numTickets, soldTickets[10];
numAgents = 10;
numTickets = 150;
for (agent = 0; agent < numAgents; agent++) {
soldTickets[agent] = 0;
}
runThreads(numAgents, numTickets, soldTickets);
// the process never executes the following block
for (agent = 0; agent < numAgents; agent++) {
printf("Agent %d sold %d ticket(s).\n", agent, soldTickets[agent]);
}
return 0;
}
pthread_exit() exits a thread, even the "main"-thread.
If main() ends all other thread go down as well.
As the "main"-thread is expected to do some final logging, it should wait until all threads spawned have ended.
To accomplish this in runThreads() replace the call to
pthread_exit(NULL);
by a loop calling pthread_join() for all PThread-IDs as returned by pthread_create().
Also you want to add error checking to all pthread*() calls, as you should do for every function call returning any relevant info, like for example indicating failure of the call.
I am trying to implement a code to practice synchronization, so might not be best design or approach but goal is as below
Main thread
Creates a payload of 100 integers and waits for any thread to be available
When it gets signal from a thread its available - it unlocks the payload for copying and proceeds to create another payload
Worker thread
on creation of it makes itself available for data processing and sends signal that its available
Tries to lock the data payload from main thread and copy it to local array
( observing bug here - not able to access data properly)
Turn off the sign of available
( unable to turn off available state to off)
Keep processing data through local copy
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#define WORKERS 2
#define ARRAY_ELEMENTS 100
#define MAX 1000
pthread_mutex_t mutex_bucket1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_signal = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_go = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_busy = PTHREAD_COND_INITIALIZER;
static int value = 0;
bool available = false;
void *worker_thread(void *pbucket)
{
sleep(5);
while(1)
{
unsigned int count = 0;
int local_array[ARRAY_ELEMENTS];
int *ptbucket = (int*)pbucket;
setbuf(stdout, NULL);
pthread_mutex_lock(&mutex_signal);
printf(" -------------- \n chainging state to available \n --------- ");
available = true;
printf(" -------------- \n from thread sending go signal \n --------- ");
pthread_cond_signal(&cond_go);
pthread_mutex_unlock(&mutex_signal);
pthread_mutex_lock(&mutex_bucket1);
printf(" -------------- \n data part locked in thread for copying \n --------- ");
while(count < ARRAY_ELEMENTS)
{
printf(" %d - \n", ptbucket[count]); /***incorrect values***/
local_array[count] = ptbucket[count];
count++;
}
pthread_mutex_unlock(&mutex_bucket1);
/*Never able to acquire mutex_signal and change state to not available*/ **BUG**
pthread_mutex_lock(&mutex_signal);
printf(" -------------- \n chainging state to not available \n --------- ");
available = false;
pthread_mutex_unlock(&mutex_signal);
count = 0;
while(count < ARRAY_ELEMENTS)
{
printf(" %d - \n", local_array[count]);
count++;
}
printf(" -------------- \n about to sleep for 5secs \n --------- ");
sleep(5);
}
}
int main(void)
{
pthread_t thread_id[WORKERS];
unsigned int* pbucket1 = (int*) malloc(sizeof(int) * ARRAY_ELEMENTS);
unsigned int* pbucket;
for(int i = 0; i < WORKERS - 1; i++)
{
pthread_create(&thread_id[i], NULL, worker_thread, (void *) pbucket);
}
for(int i = 0; i < MAX; i++)
{
unsigned int count = 0;
pbucket = pbucket1;
// Make the payload ready
pthread_mutex_lock(&mutex_bucket1);
printf(" -------------- creating data payload --------- \n");
while(count < ARRAY_ELEMENTS)
{
pbucket1[count] = i;
i++;
count++;
}
printf(" -------------- \n waiting for go signal \n --------- ");
while(!available)
{
pthread_cond_wait(&cond_go, &mutex_signal);
}
pthread_mutex_unlock(&mutex_bucket1);
/*I believe after we unlock variable "available" can be mutexed
again by other thread but seems thinking is flawed */
printf(" -------------- \n Main thread sleep for 3 seconds \n --------- ");
sleep(3);
}
for(int i = 0; i < WORKERS; i++)
{
pthread_join(thread_id[i], NULL);
}
return 0;
}
I think some of your idea is backwards; It shouldn't be the main context that is waiting, it should be the worker threads waiting for data ...
The job of the main thread should be to keep populating the payload and waking one thread at a time to process it.
So here's some scribbled code that is a little more sensible, I think:
/**
file: answer.c
compile: gcc -o answer answer.c -pthread
usage: answer [numThreads] [numElements]
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define STATE_WAIT 1
#define STATE_READY 2
void *routine(void*);
typedef struct _shared_t {
pthread_mutex_t m;
pthread_cond_t c;
unsigned char state;
int *payload;
size_t numElements;
pthread_t *threads;
size_t numThreads;
} shared_t;
static inline void shared_init(shared_t *shared, size_t numThreads, size_t numElements) {
memset(shared, 0, sizeof(shared_t));
pthread_mutex_init(&shared->m, NULL);
pthread_cond_init(&shared->c, NULL);
shared->state = STATE_WAIT;
shared->numThreads = numThreads;
shared->numElements = numElements;
{
int it = 0;
shared->threads = (pthread_t*) calloc(shared->numThreads, sizeof(pthread_t));
while (it < shared->numThreads) {
if (pthread_create(&shared->threads[it], NULL, routine, shared) != 0) {
break;
}
it++;
}
}
}
static inline void shared_populate(shared_t *shared) {
if (pthread_mutex_lock(&shared->m) != 0) {
return;
}
shared->payload = (int*) calloc(shared->numElements, sizeof(int));
{
int it = 0,
end = shared->numElements;
while (it < end) {
shared->payload[it] = rand();
it++;
}
}
shared->state = STATE_READY;
pthread_cond_signal(&shared->c);
pthread_mutex_unlock(&shared->m);
}
static inline void shared_cleanup(shared_t *shared) {
int it = 0,
end = shared->numThreads;
while (it < end) {
pthread_join(shared->threads[it], NULL);
}
pthread_mutex_destroy(&shared->m);
pthread_cond_destroy(&shared->c);
free(shared->threads);
}
void* routine(void *arg) {
shared_t *shared = (shared_t*) arg;
int *payload;
do {
if (pthread_mutex_lock(&shared->m) != 0) {
break;
}
while (shared->state == STATE_WAIT) {
pthread_cond_wait(&shared->c, &shared->m);
}
payload = shared->payload;
shared->state = STATE_WAIT;
pthread_mutex_unlock(&shared->m);
if (payload) {
int it = 0,
end = shared->numElements;
while (it < end) {
printf("Thread #%ld got payload %p(%d)=%d\n",
pthread_self(), payload, it, payload[it]);
it++;
}
free(payload);
}
} while(1);
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
shared_t shared;
int numThreads = argc > 1 ? atoi(argv[1]) : 1;
int numElements = argc > 2 ? atoi(argv[2]) : 100;
shared_init(&shared, numThreads, numElements);
do {
shared_populate(&shared);
} while (1);
shared_cleanup(&shared);
return 0;
}
Obviously, the code above is not very tolerant of errors, and is not easy to shutdown cleanly ... it's illustration only.
Let's first look at main so that we know what the flow of the main program is going to be:
int main(int argc, char *argv[]) {
shared_t shared;
int numThreads = argc > 1 ? atoi(argv[1]) : 1;
int numElements = argc > 2 ? atoi(argv[2]) : 100;
shared_init(&shared, numThreads, numElements);
do {
shared_populate(&shared);
} while (1);
shared_cleanup(&shared);
return 0;
}
It keeps a shared_t on the stack:
typedef struct _shared_t {
pthread_mutex_t m;
pthread_cond_t c;
unsigned char state;
int *payload;
size_t numElements;
pthread_t *threads;
size_t numThreads;
} shared_t;
Mostly self explanatory, mutex, condition and state are required for synchronization.
First of all the shared_t must be initialized with mutex, condition, state and threads using the provided options:
static inline void shared_init(shared_t *shared, size_t numThreads, size_t numElements) {
memset(shared, 0, sizeof(shared_t));
pthread_mutex_init(&shared->m, NULL);
pthread_cond_init(&shared->c, NULL);
shared->state = STATE_WAIT;
shared->numThreads = numThreads;
shared->numElements = numElements;
{
int it = 0;
shared->threads = (pthread_t*) calloc(shared->numThreads, sizeof(pthread_t));
while (it < shared->numThreads) {
if (pthread_create(&shared->threads[it], NULL, routine, shared) != 0) {
break;
}
it++;
}
}
}
When the worker threads are created by this routine, they are forced into a waiting state.
The first call to shared_populate in the loop awakens the first thread after setting the payload to some random numbers:
static inline void shared_populate(shared_t *shared) {
if (pthread_mutex_lock(&shared->m) != 0) {
return;
}
shared->payload = (int*) calloc(shared->numElements, sizeof(int));
{
int it = 0,
end = shared->numElements;
while (it < end) {
shared->payload[it] = rand();
it++;
}
}
shared->state = STATE_READY;
pthread_cond_signal(&shared->c);
pthread_mutex_unlock(&shared->m);
}
Note the use of pthread_cond_signal over pthread_cond_broadcast, because we only want to wake the first thread.
void* routine(void *arg) {
shared_t *shared = (shared_t*) arg;
int *payload;
do {
if (pthread_mutex_lock(&shared->m) != 0) {
break;
}
while (shared->state == STATE_WAIT) {
pthread_cond_wait(&shared->c, &shared->m);
}
payload = shared->payload;
shared->state = STATE_WAIT;
pthread_mutex_unlock(&shared->m);
if (payload) {
int it = 0,
end = shared->numElements;
while (it < end) {
printf("Thread #%ld got payload %p(%d)=%d\n",
pthread_self(), payload, it, payload[it]);
it++;
}
free(payload);
}
} while(1);
pthread_exit(NULL);
}
So we wake up in routine at the call to pthread_cond_wait, the state has changed, so we break out of the loop, we save the pointer to the payload, reset the state to WAIT, and release the mutex.
At this point main can repopulate the payload and awaken the next thread, meanwhile the current worker thread can process, and then free the payload.
Some advice:
Always use as few mutex and condition variables as possible (KISS)
Research the atomic nature of condition variables
Always follow the basic rules regarding acquisition and release of mutex and signaling of condition variables:
If you locked it, unlock it.
Only ever wait for something: predicated wait loops are absolutely required, all the time.
If you can't reproduce what I done, then take the code and try to expand upon it; The first thing you need to do is be able to shutdown the process gracefully (enter shared_cleanup), maybe you need a variable sized payload, or some other requirement not mentioned in the original question.
Note about printf ... appending to a stream is not guaranteed to be atomic, it so happens that most of the time on *nix it is ... since we are just doing show and tell, we don't need to care about that ... ordinarily, do not rely on atomicity for any stream operations ...