Producer - Consumer Problem in Multi-Threading in C (Condition Variables) - c

I am trying to solve the problem of consumer-producer with condition variables,
i just want to know if my code resolves the problem correctly.
PS:i can put while(1) instead of while(x<100) but i want to see the execution and check if there is missed numbers,
my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#define THREAD_NUM 2
pthread_cond_t full;
pthread_cond_t empty;
pthread_mutex_t mutexBuffer;
int buffer[10];
int count = 0;//the index of where the consume/produce should be in the buffer
void* producer(void* args) {
// int i=1;
int x = 1;
while (x<100)
{
// Produce
// Add to the buffer
pthread_mutex_lock(&mutexBuffer);
if (count<10)
{
buffer[count]= x;
count++;
pthread_cond_signal(&empty);
x++;
}
else
{
pthread_cond_wait(&full,&mutexBuffer);
buffer[count]= x;
count++;
x++;
}
pthread_mutex_unlock(&mutexBuffer);
}
}
void* consumer(void* args) {
int cpt=0;//to stop the while after execution 100 times
while (1) {
int y=-1;
// Remove from the buffer
pthread_mutex_lock(&mutexBuffer);
if (count>0)
{
y = buffer[count - 1];
count--;
pthread_cond_signal(&full);
}
else
{
pthread_cond_wait(&empty,&mutexBuffer);
y = buffer[count - 1];
count--;
printf("nothing is lost!\n");
}
printf("Got %d\n", y);
cpt++;
pthread_mutex_unlock(&mutexBuffer);
if(cpt==99)break;
}
}
int main(int argc, char* argv[]) {
srand(time(NULL));
pthread_t th[THREAD_NUM];
pthread_mutex_init(&mutexBuffer, NULL);
int i;
for (i = 0; i < THREAD_NUM; i++) {
if (i%2==0) {
if (pthread_create(&th[i], NULL, &producer, NULL) != 0) {
perror("Failed to create thread");
}
} else {
if (pthread_create(&th[i], NULL, &consumer, NULL) != 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");
}
}
pthread_mutex_destroy(&mutexBuffer);
return 0;
}
and i have a question also,When using semaphore is better than condition variable,or the inverse?

Related

Can't I send 2 messages with different key with message queue with child-parent IPC in C?

Trying to send 2 different integers with 2 different keys in same function. but lower one doesn't actually work and only show -1 value.
Child is sending 2 messages, and parent receives it.
and parent's printf receives it with msgrcv, and should show its pid and cpu_burst value.
Tried compiling with gcc, but child() still skips while(sunstatus) and go direct to printf and returns 0.
This is my code.
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <signal.h>
#include "msg_cm.h"
#include "runq.h"
#include "waitq.h"
#include "cidq.h"
void timer_handler(int signum) {
int temp = runq[0];
putwtq(temp);
rmvrnq();
}
int child(int key, int quant){
int cpid = getpid();
srand(cpid);
int cpu_burst = rand() % 100 + 6;
int io_burst = rand() % 100 + 1;
msg_sndr(key, cpid);
msg_sndr(cpid, cpu_burst);
int runstatus = 1;
int onoffchk = 0;
while(runstatus) {
if (msg_rcvr(getpid()) > 0) {
onoffchk = 1 - onoffchk;
}
if (onoffchk == 1) {
cpu_burst = cpu_burst - quant;
}
}
printf("Child process terminated.\n");
msg_sndr(5678, 3);
return 0;
}
int main() {
int temp = 500000;
int cnt = 1;
int pid;
int quantum = 5;
int count = 9;
int comp[10];
while(temp > 0) {
msg_rcvr(1234);
temp = temp -1;
}
printf("Parent running: %d\n", getpid());
for (int i = 0; i < 10; i++) {
pid = fork();
if(pid == 0) {
break;
}
else if (pid > 0) {
printf("Child process : %d created.\n", pid);
}
else {
printf("fork() failed!!!");
return -1;
}
}
if(pid == 0) {
child(1234, quantum);
}
else {
int tick = 1;
int end = 10;
struct sigaction sigac;
struct itimerval timer;
struct itimerval stoptimer;
sigac.sa_handler = timer_handler;
sigaction(SIGALRM, &sigac, NULL);
timer.it_value.tv_sec = quantum;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = quantum;
timer.it_interval.tv_usec = 0;
stoptimer.it_value.tv_sec = 0;
stoptimer.it_value.tv_sec = 0;
stoptimer.it_interval.tv_sec = 0;
stoptimer.it_interval.tv_sec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
while(end > 1){
if (msg_rcvr(5678) > 0) {
end--;
setitimer(ITIMER_REAL, &stoptimer, NULL);
setitimer(ITIMER_REAL, &timer, NULL);
}
if (msg_exist(1234) != 2) {
putrnq(msg_rcvr(1234));
}
if (runq[0] == -1) {
printf("%d\tidle\n",tick);
}
else {
printf("%d\tProcess: %d running...\tCPU burst: %d", tick, runq[0], msg_rcvr(runq[0]));
}
tick++;
sleep(1);
}
printf("All childs are terminated.\n");
}
return 0;
}
msg_cm.h
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msgdata {
long int msg_type;
int text;
}message;
int msg_sndr(int key, int num) {
int msgid;
struct msgdata message;
char buf[20];
msgid = msgget((key_t)key, 0666 | IPC_CREAT);
if (msgid == -1) {
printf("error while creating msg q!!!");
return -1;
}
message.msg_type = 1;
message.text = num;
if (msgsnd(msgid, (void *)&message, sizeof(message), 0) == -1) {
printf("msg not sent!!!");
return -1;
}
}
int msg_rcvr(int key) {
int msgid;
struct msgdata message;
long int msg_to_rec = 0;
msgid = msgget((key_t)key, 0666| IPC_CREAT);
if (msgrcv(msgid, (void *)&message, sizeof(message), msg_to_rec, 0 | IPC_NOWAIT) > 0) {
return message.text;
}
else {
return -1;
}
msgctl(msgid, IPC_RMID, 0);
}
int msg_exist(int key) {
int msgid;
msgid = msgid = msgget((key_t)key, 0666| IPC_CREAT);
struct msqid_ds buf;
int rc = msgctl(msgid, IPC_STAT, &buf);
unsigned int msg = (unsigned int)(buf.msg_qnum);
rc = msgctl(msgid, IPC_STAT, &buf);
msg = (uint)(buf.msg_qnum);
if (msg > 0) {
return 1;
}
else {
return 2;
}
}
*all of idq.h
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int cburstq[20];
int ccount = 0;
void putidq(int num) {
cburstq[ccount] = num;
ccount++;
}
int rmvidq() {
int tmp = cburstq[0];
for (int tmpnm = 0; tmpnm < ccount; tmpnm++){
cburstq[tmpnm] = cburstq[tmpnm + 1];
}
ccount--;
return tmp;
}

How to implement global POSIX semaphore to be used by two C programs?

I have two C files: a.c (master) and b.c (follower).
I want to create a synchronization between master and follower using a semaphore.
According to what I have learnt I need to have a global POSIX semaphore to make this work.
How can I implement this in the b.c (follower) file using only the semaphores in a.c (master)?
Semaphore implemented for a.c file (master):
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
sem_t x,y;
pthread_t tid;
pthread_t writerthreads[100],readerthreads[100];
int readercount = 0, writercount = 0;
void* reader(void* param)
{
if (writercount > 0) {
sem_wait(&x);
readercount++;
if (readercount == 1) {
sem_wait(&y);
}
sem_post(&x);
printf("%d reader is inside\n",readercount);
//read all the files in the directory
sleep(3);
sem_wait(&x);
readercount--;
if (readercount == 0) {
sem_post(&y);
}
sem_post(&x);
printf("%d Reader is leaving\n",readercount+1);
} else {
printf("Nothing to view\n");
}
return NULL;
}
void* writer(void* param)
{
printf("Master is trying to upload\n");
sem_wait(&y);
printf("Master is uploading\n");
//create file in a directory
sem_post(&y);
writercount++;
printf("Master is leaving\n");
return NULL;
}
int main()
{
int a,i = 0,b;
sem_init(&x,0,1);
sem_init(&y,0,1);
while (1) {
printf("Enter 1 to View / 2 to Upload / 3 to Exit:");
scanf("%d",&b);
if (b == 1) {
pthread_create(&readerthreads[i],NULL,reader,NULL);
} else if (b == 2) {
pthread_create(&writerthreads[i],NULL,writer,NULL);
} else {
exit(0);
}
pthread_join(writerthreads[i],NULL);
pthread_join(readerthreads[i],NULL);
i++;
}
return 0;
}
Semaphore in the b.c file (follower):
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
sem_t x,y;
pthread_t tid;
pthread_t readerthreads[100];
int readercount = 0, writercount = 0;
void* reader(void* param)
{
if (writercount > 0) {
sem_wait(&x);
readercount++;
if (readercount == 1) {
sem_wait(&y);
}
sem_post(&x);
printf("%d Follower is inside\n",readercount);
//read all the files in the directory
sleep(3);
sem_wait(&x);
readercount--;
if (readercount == 0) {
sem_post(&y);
}
sem_post(&x);
printf("%d Follower is leaving\n",readercount+1);
} else {
printf("Nothing to view\n");
}
return NULL;
}
int main()
{
int a,i = 0,b;
sem_init(&x,0,1);
sem_init(&y,0,1);
while (1) {
printf("Enter 1 to View / 3 to Exit:");
scanf("%d",&b);
if (b == 1) {
pthread_create(&readerthreads[i],NULL,reader,NULL);
} else {
exit(0);
}
pthread_join(readerthreads[i],NULL);
i++;
}
}
Having two different process, you have to use named semaphore, like described here:
Share POSIX semaphore among multiple processes
So your code can be edited like
a.c
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <fcntl.h>
sem_t *x,*y;
pthread_t tid;
pthread_t writerthreads[100],readerthreads[100];
int readercount = 0, writercount = 0;
void* reader(void* param)
{
if (writercount > 0) {
sem_wait(x);
readercount++;
if (readercount == 1) {
sem_wait(y);
}
sem_post(x);
printf("%d reader is inside\n",readercount);
//read all the files in the directory
sleep(3);
sem_wait(x);
readercount--;
if (readercount == 0) {
sem_post(y);
}
sem_post(x);
printf("%d Reader is leaving\n",readercount+1);
} else {
printf("Nothing to view\n");
}
return NULL;
}
void* writer(void* param)
{
printf("Master is trying to upload\n");
sem_wait(y);
printf("Master is uploading\n");
//create file in a directory
sem_post(y);
writercount++;
printf("Master is leaving\n");
return NULL;
}
int main()
{
int a,i = 0,b;
x = sem_open("/semaphore_x", O_CREAT | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 1);
y = sem_open("/semaphore_y", O_CREAT | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO, 1);
if( x == NULL || y == NULL) {
printf("Unable to open named semaphores\n");
exit(-1);
}
while (1) {
printf("Enter 1 to View / 2 to Upload / 3 to Exit:");
scanf("%d",&b);
if (b == 1) {
pthread_create(&readerthreads[i],NULL,reader,NULL);
} else if (b == 2) {
pthread_create(&writerthreads[i],NULL,writer,NULL);
} else {
sem_close(x);
sem_close(y);
sem_unlink("/semaphore_x");
sem_unlink("/semaphore_y");
exit(0);
}
pthread_join(writerthreads[i],NULL);
pthread_join(readerthreads[i],NULL);
i++;
}
return 0;
}
and b.c
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <fcntl.h>
sem_t *x,*y;
pthread_t tid;
pthread_t readerthreads[100];
int readercount = 0, writercount = 0;
void* reader(void* param)
{
if (writercount > 0) {
sem_wait(x);
readercount++;
if (readercount == 1) {
sem_wait(y);
}
sem_post(x);
printf("%d Follower is inside\n",readercount);
//read all the files in the directory
sleep(3);
sem_wait(x);
readercount--;
if (readercount == 0) {
sem_post(y);
}
sem_post(x);
printf("%d Follower is leaving\n",readercount+1);
} else {
printf("Nothing to view\n");
}
return NULL;
}
int main()
{
int a,i = 0,b;
x = sem_open("/semaphore_x", O_RDWR);
y = sem_open("/semaphore_y", O_RDWR);
if( x == NULL || y == NULL) {
printf("Unable to open named semaphores\n");
exit(-1);
}
while (1) {
printf("Enter 1 to View / 3 to Exit:");
scanf("%d",&b);
if (b == 1) {
pthread_create(&readerthreads[i],NULL,reader,NULL);
} else {
sem_close(x);
sem_close(y);
exit(0);
}
pthread_join(readerthreads[i],NULL);
i++;
}
}

C Threaded while loop not running

I want a threaded while loop that forever increments i. Why does it stop prematurely?
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
void *increment () {
int i = 0;
while (1) {
i++;
printf("Number: %d", i);
}
}
int main (int argc, char **argv) {
if (argc <= 1) {
fprintf(stderr, "Invalid params\n");
exit(-1);
}
int num_threads = atoi(argv[1]);
pthread_t thread[num_threads];
for (int i = 0; i < num_threads; i++) {
pthread_create(&thread[i], NULL, &increment, argv[1]);
}
return 0;
}
just put
while(1);
before the return in main if you just want the created thread to run forever
E.g.
int main (int argc, char **argv) {
if (argc <= 1) {
fprintf(stderr, "Invalid params\n");
exit(-1);
}
int num_threads = atoi(argv[1]);
pthread_t thread[num_threads];
for (int i = 0; i < num_threads; i++) {
pthread_create(&thread[i], NULL, &increment, argv[1]);
}
while(1) ; // don't exit the main thread
// while (1) sleep(1000) ; // would be better
return 0;
}

Getting bad address when I fork?

So I have three files: Pellets.c, Fish.c, and SwimMill.c. SwimMill calls Pellets and Fish, which should fork. However, when I try to fork Pellets, i get an error saying "Pellet fork failed: Bad Address". Anyone know what the problem is?
include.h
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#define SHM_SIZE 1000
int shmid;
int *shm;
pid_t fish;
pid_t pellet;
void attachSharedMemory() {
key_t key = ftok("SwimMill.c", 'b'); //generate random key
shmid = shmget(key, SHM_SIZE, IPC_CREAT|0666);
shm = shmat(shmid, NULL, 0);
}
SwimMill.c
// Uses both fish and pellets, 30 seconds, then print it out
// Create pellets at random intervals, from 0x80
// Eating --> Get rid of most significant bit
// Use shared memory for fish and pellet position only
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "include.h"
#define SHM_SIZE 1000
void printGrid(int*);
void handler(int);
void killProgram(pid_t, pid_t, int*, int);
pid_t fish;
pid_t pellet;
int main(int argc, char* argv[]) {
int timer = 0;
attachSharedMemory(); // from include.h
signal(SIGINT, handler);
// Initializing the shared memory to prevent segmentation fault
// for (int i = 0; i < SHM_SIZE; i++){
// shm[i] = -1;
// }
srand(time(NULL));
fish = fork();
if (fish == -1) {
perror("Fish fork failed1");
exit(1);
} else if (fish == 0) {
execv("Fish", argv);
perror("Fish exec failed");
exit(1);
}
while(timer <= 30){
pellet = fork();
if (pellet == -1) {
perror("Pellet Fork failed1");
exit(1);
} else if (pellet == 0) {
execv("Pellets", argv);
perror("Pellets Fork failed");
exit(1);
}
printGrid(shm);
sleep(1);
printf("Timer: %d\n", timer);
timer++;
}
killProgram(fish, pellet, shm, shmid);
getchar(); // Pause consol
return 0;
}
void printGrid(int* shm) {
int row = 10;
int column = 10;
char (*stream)[row][column]; //2D Dimensional array, fish can only move last row of 2d
//Initializing grid first
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
(*stream)[i][j] = '~';
}
}
printf("Fish: %d \n", shm[0]);
printf("Shm2 is: %d \n", shm[1] );
for (int k = 1; k < 20; k++) {
(*stream)[shm[k]/10][shm[k]%10] = 'O'; // pellets
}
(*stream)[shm[0]/10][shm[0]%10] = 'Y'; // Fish
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
printf("%c ", (*stream)[i][j]);
}
printf("\n");
}
}
void killProgram(pid_t fish, pid_t pellet, int *shm, int shmid) {
kill(fish,SIGUSR1);
kill(pellet, SIGUSR1);
sleep(5);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
printf("Program finished! \n");
}
void handler(int num ) {
kill(fish,SIGUSR1);
kill(pellet, SIGUSR1);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
perror(" Interrupt signal is pressed!! \n");
exit(1);
}
Pellets.c
// Multiple pellets
//Process ID, position, eaten/misse
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include "include.h"
#define SHM_SIZE 1000
void handler(int);
void eatPellet();
void missPellet();
int main(int argc, char* argv[]) {
signal(SIGINT, handler);
attachSharedMemory();
srand(time(NULL));
int i = 1; // 1 - 19 are pellets
for (; i < 20; i++) {
int pelletPosition = rand() % 9 ; // random number from 0 - 9
if (shm[i] == -1){
// printf("hello %d \n", pelletPosition);
shm[i] = pelletPosition;
}
break;
}
while(1) {
printf("helloasd %d \n", shm[i]);
printf("i: %d \n", i);
if (shm[i] < 90) {
shm[i] += 10;
}
else if (shm[i] == shm[0]) {
eatPellet();
printf("Position: %d\n", shm[i] );
break;
// EATEN and KILL
}
else {
// KIll process, terminate
missPellet();
printf("Position: %d\n", shm[i] );
break;
}
// printf("%d\n",shm[i] );
i++;
sleep(1);
}
shmdt(shm);
return 0;
}
void handler(int num) {
shmdt(shm);
exit(1);
}
I looked at other stack overflow questions, and it seems that they problems because they didn't terminate with a NULL? I think the problem lies inside Pellets.c, but I can't seem to figure it out. Thanks.

In C, I want to access one array in two separate processes [duplicate]

This question already has answers here:
How to use shared memory with Linux in C
(5 answers)
Closed 4 years ago.
This is essentially what I want to do, but the outputs are junk data. What are some of the different options I have for making the child's array visible from inside the parent process?
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int foo[3]; //initialize array
pid_t pid;
pid = fork(); //create child thread
if (pid == 0) { //child:
foo[0] = 0; foo[1] = 1; foo[2] = 2; //populate array
}
else { //parent:
wait(NULL); //wait for child to finish
printf("%d %d %d", foo[0], foo[1], foo[2]); //print contents of array
}
return 0;
}
Using mmap you can create a shared memory block in your parent process. This is a basic example removing error checking for brevity.
You want to sure the proper protections and flags are set for your needs. Then hand off the address returned by mmap to your child process.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#define LIMIT_MAP 5
void child_worker(void *map)
{
int map_value = -1;
int idx = 0;
while (map_value != LIMIT_MAP) {
map_value = *((int *) map + (idx * sizeof(int)));
printf("Map value: %d\n", map_value);
idx++;
sleep(2);
}
}
int main(int argc, char *argv[])
{
printf("Starting Parent Process...\n");
long page_size = sysconf(_SC_PAGESIZE);
void *memory_map = mmap(0, page_size, PROT_WRITE | PROT_READ,
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
printf("Memory map created: <%p>\n", memory_map);
pid_t pid = fork();
if (pid == 0) {
sleep(1);
printf("Starting child process\n");
child_worker(memory_map);
printf("Exiting child process...\n");
return 0;
} else {
printf("Continuing in parent process\n");
int set_values[5] = { 1, 2, 3, 4, 5 };
for (int i=0; i < 5; i++) {
printf("Setting value: %d\n", set_values[i]);
*((int *) memory_map + (sizeof(int) * i)) = set_values[i];
sleep(1);
}
waitpid(pid, NULL, 0);
printf("Child process is finished!\n");
}
return 0;
}
If fork isn't a requirement and your platform allows for it, pthread is one option. Depending on how your array is being operated on, create a thread pool passing each worker thread a copy of your array.
This is a contrived example but maybe you can pull something from it:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#define THREAD_COUNT 3
#define ITER_LIMIT 7
struct worker_params {
int idx;
int max;
bool done;
double *data;
double condition;
};
void *worker(void *arg)
{
struct worker_params *wp = (struct worker_params *) arg;
int count = 0;
while ( 1 ) {
wp->data[wp->idx] = drand48();
if (wp->max == count)
wp->done = true;
sleep(1);
count++;
}
return NULL;
}
int main(int argc, char *argv[])
{
double data[THREAD_COUNT] = { 0.0 };
pthread_t worker_1, worker_2, worker_3;
pthread_t worker_threads[] = { worker_1, worker_2, worker_3 };
struct worker_params wps[] = {
{ .idx=0, .condition=0.1, .data=data, .done=0 },
{ .idx=1, .condition=0.2, .data=data, .done=0 },
{ .idx=2, .condition=0.3, .data=data, .done=0},
};
for (int i=0; i < THREAD_COUNT; i++) {
wps[i].max = (rand() % ITER_LIMIT) + 2;
pthread_create(&worker_threads[i], NULL, worker, (void *) &wps[i]);
}
// Continue on main execution thread
int running = 1;
while ( running ) {
for (int i=0; i < THREAD_COUNT; i++) {
if (wps[i].done) {
printf("Limit hit in worker <%d>\n", i + 1);
running = 0;
break;
}
printf("Data in worker <%d> :: %g\n", i + 1, wps[i].data[i]);
}
sleep(1);
}
return 0;
}

Resources