The product type should be 1 or 2 depending on the process that created the product
product id should increase by one each time one is produced
consumer id will always be 1,2,3, or 4 depending on which thread consumer consumes the product
consumer count will increase by 1 each time one is consumed
And product type should only be 1 or 2
i think i need to change the code up a bit and add condition variables and locks .But stuck at that
I have most of it done but it has some issues.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdbool.h>
#include <fcntl.h>
#include <pthread.h>
#define BUFFER_SIZE1 20
#define BUFFER_SIZE2 30
typedef struct
{
int count;
int productType;
} product;
int count = 0;
int fd[2];
pthread_mutex_t lock;
pthread_cond_t cond;
typedef struct
{
product *values;
int head;
int tail;
int numEntries;
int size;
} queue;
queue q1;
queue q2;
void producer(int args);
void *consumer(void *args);
void *distributor(void *args);
void initQ(queue *q, int size);
bool QEmpty(queue *q);
bool QFull(queue *q);
bool put(queue *q, product prod);
product get(queue *q);
// https://www.youtube.com/watch?v=l6zkaJFjUbM
// https://www.geeksforgeeks.org/multithreading-c-2/
int main(int argc, char const *argv[])
{
// Creating 5 threads 4 consumer and 1 distributor
pthread_t th[5];
// Creating our pipe, fd[0] is read end, fd[1] is write end
if (pipe(fd) == -1)
{
perror("error creating pipe");
exit(1);
}
// Initializing both buffers
initQ(&q1, BUFFER_SIZE1);
initQ(&q2, BUFFER_SIZE2);
int pid1;
int pid2;
int consId1 = 1;
int consId2 = 2;
// Initializing lock
pthread_mutex_init(&lock, NULL);
// Initialziing condition variables
pthread_cond_init(&cond, NULL);
// Create first producer process using fork(), child process 1
pid1 = fork();
if (pid1 == 0)
{
producer(1);
}
// Create second prodcuer process using fork(), child process 2
pid2 = fork();
if ( pid2== 0)
{
producer(2);
}
// Create distrubtor and consumer threads, parent process
else
{
// Creating 4 threads using for loop and pthread_create
for (int i = 0; i < 4; i++)
{
// 2 consumer threads for product type 1
if (i == 1 || i == 2)
{
if (pthread_create(&th[i], NULL, &consumer, &consId1) != 0)
{
perror("Error creating thread");
}
}
// 2 consumer threads for product type 2
else
{
if (pthread_create(&th[i], NULL, &consumer, &consId2) != 0)
{
perror("Error creating thread");
}
}
}
// use pthread_join to wait for preivous thread to terminate
for (int i = 0; i < 4; i++)
{
if (pthread_join(th[i], NULL) != 0)
{
perror("Error joining thread");
}
}
// Distributor thread
close(fd[1]);
while (1)
{
product prod;
// Using lock and condition variable around crit section to avoid race condition
// pthread_mutex_lock(&lock);
// pthread_cond_wait(&cond, &lock);
// Read from the pipe
read(fd[0], &prod, sizeof(prod));
if (prod.productType == 1)
{
put(&q1, prod);
}
else
{
put(&q2, prod);
}
}
// pthread_cond_signal(&cond);
// pthread_mutex_unlock(&lock);
// Close read end of the pipe
close(fd[0]);
}
return 0;
}
// Creating the producers
void producer(int args)
{
int prodCount = 0;
product prod;
prod.productType = args;
// Close read end of the pipe
close(fd[0]);
while (1)
{
prodCount++;
prod.count = prodCount;
// Send product to the pipe so the consumer can use
write(fd[1], &prod, sizeof(prod));
// Sleep for 0.01 - 0.2 seconds after each loop
int time = (rand() % (200000 - 10000 + 1)) + 10000;
usleep(time);
}
// Close write end of the pipe
close(fd[1]);
}
void *consumer(void *args)
{
int consCount1;
int consCount2;
FILE *fp;
fp = fopen("output.txt", "w");
product prod;
int prodType = *(int *)args;
while (1)
{
if (prodType == 1)
{
get(&q1);
consCount1++;
fputs("Thread ID: \n", fp);
fprintf(fp, "Product Type: %d\n", prod.productType);
fprintf(fp, "Production Sequence #: %d\n", prod.count);
fprintf(fp, "Consumption Sequence #: %d\n", consCount1);
}
else
{
get(&q2);
consCount2++;
fputs("Thread ID: 2\n", fp);
fprintf(fp, "Product Type: %d\n", prod.productType);
fprintf(fp, "Production Sequence #: %d\n", prod.count);
fprintf(fp, "Consumption Sequence #: %d\n", consCount2);
}
}
fclose(fp);
}
// https://www.youtube.com/watch?v=oyX30WVuEos&t=196s
// Circular buffer
void initQ(queue *q, int size)
{
q->size = size;
q->values = malloc(sizeof(product) * q->size);
q->numEntries = 0;
q->head = NULL;
q->tail = NULL;
}
// Checks if the queue is empty
bool QEmpty(queue *q)
{
return (q->numEntries == 0);
}
// Checks if the queue is full
bool QFull(queue *q)
{
return (q->numEntries == q->size);
}
// Used for adding products to the queue
bool put(queue *q, product prod)
{
// If the queue is full we can not add to it
if (QFull(q))
{
return false;
}
// Add product to the end of the queue
q->values[q->tail] = prod;
q->numEntries++;
// Move index of the tail
q->tail = (q->tail + 1);
// If index goes out of bounds set back to 0
if (q->tail >= q->size)
{
q->tail = 0;
}
return true;
}
// Used for removing products for the queue
product get(queue *q)
{
product result;
// If the queue is empty we can not dequeue anymore
if (QEmpty(q))
{
perror("Error on dequeue");
}
// Remove from the head of the queue
result = q->values[q->head];
q->head = (q->head + 1) & q->size;
q->numEntries--;
return result;
}
Related
I need help with my c program, I have most of it done but it has some issues.
The program is about ** Exploring Synchronization Among Processes and Threads.**
You are given three (3) processes in one program that work together to solve a producer consumer problem:
2 processes are “producers” and each process produces its own type of product in a continuous loop. That is, one product type produced by one producer and a different product type by the other producer.
One Process is a “consumer” of products and consist of five (5) threads:
1 thread is a ‘distributor’ thread
two (2) threads consume one type of product (ex. consumes only product type 1)
two (2) threads consume a second type of product (ex. consumes only product type 2).
The consumer process contains two (2) product storage buffers, each comprised of a fixed number of slots. The number of slots in the buffers are to be different (one has more slots than
the other). You choose and specify the number of slots in each buffer as a definition in your
program solution
Communication between the producer processes and the consumer process is to be through a
single “pipe”. This single, shared pipe is used to communicate between each producer process
and the consumer process. Each producer process writes into this pipe the product to be
consumed by the consumer process.
Final program delivery: completion of the product consumer threads, output file design and
write functions; sample data runs with output files
I have most of it done but it has some issues.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdbool.h>
#include <fcntl.h>
#include <pthread.h>
#define BUFFER_SIZE1 20
#define BUFFER_SIZE2 30
typedef struct
{
int count;
int productType;
} product;
int count = 0;
int fd[2];
pthread_mutex_t lock;
pthread_cond_t cond;
typedef struct
{
product *values;
int head;
int tail;
int numEntries;
int size;
} queue;
queue q1;
queue q2;
void producer(int args);
void *consumer(void *args);
void *distributor(void *args);
void initQ(queue *q, int size);
bool QEmpty(queue *q);
bool QFull(queue *q);
bool put(queue *q, product prod);
product get(queue *q);
// https://www.youtube.com/watch?v=l6zkaJFjUbM
// https://www.geeksforgeeks.org/multithreading-c-2/
int main(int argc, char const *argv[])
{
// Creating 5 threads 4 consumer and 1 distributor
pthread_t th[5];
// Creating our pipe, fd[0] is read end, fd[1] is write end
if (pipe(fd) == -1)
{
perror("error creating pipe");
exit(1);
}
// Initializing both buffers
initQ(&q1, BUFFER_SIZE1);
initQ(&q2, BUFFER_SIZE2);
int pid1;
int pid2;
int consId1 = 1;
int consId2 = 2;
// Initializing lock
pthread_mutex_init(&lock, NULL);
// Initialziing condition variables
pthread_cond_init(&cond, NULL);
// Create first producer process using fork(), child process 1
if (pid1 = fork() == 0)
{
producer(1);
}
// Create second prodcuer process using fork(), child process 2
else if (pid2 = fork() == 0)
{
producer(2);
}
// Create distrubtor and consumer threads, parent process
else
{
// Creating 4 threads using for loop and pthread_create
for (int i = 0; i < 4; i++)
{
// 2 consumer threads for product type 1
if (i == 1 || i == 2)
{
if (pthread_create(&th[i], NULL, &consumer, &consId1) != 0)
{
perror("Error creating thread");
}
}
// 2 consumer threads for product type 2
else
{
if (pthread_create(&th[i], NULL, &consumer, &consId2) != 0)
{
perror("Error creating thread");
}
}
}
// use pthread_join to wait for preivous thread to terminate
for (int i = 0; i < 4; i++)
{
if (pthread_join(th[i], NULL) != 0)
{
perror("Error joining thread");
}
}
// Distributor thread
close(fd[1]);
while (1)
{
product prod;
// Using lock and condition variable around crit section to avoid race condition
// pthread_mutex_lock(&lock);
// pthread_cond_wait(&cond, &lock);
// Read from the pipe
read(fd[0], &prod, sizeof(prod));
if (prod.productType == 1)
{
put(&q1, prod);
}
else
{
put(&q2, prod);
}
}
// pthread_cond_signal(&cond);
// pthread_mutex_unlock(&lock);
// Close read end of the pipe
close(fd[0]);
}
return 0;
}
// Creating the producers
void producer(int args)
{
int prodCount = 0;
product prod;
prod.productType = args;
// Close read end of the pipe
close(fd[0]);
while (1)
{
prodCount++;
prod.count = prodCount;
// Send product to the pipe so the consumer can use
write(fd[1], &prod, sizeof(prod));
// Sleep for 0.01 - 0.2 seconds after each loop
int time = (rand() % (200000 - 10000 + 1)) + 10000;
usleep(time);
}
// Close write end of the pipe
close(fd[1]);
}
void *consumer(void *args)
{
int consCount1;
int consCount2;
FILE *fp;
fp = fopen("output.txt", "w");
product prod;
int prodType = *(int *)args;
while (1)
{
if (prodType == 1)
{
get(&q1);
consCount1++;
fprintf("Thread ID: %d\n", prodType);
fprintf(fp, "Product Type: %d\n", prod.productType);
fprintf(fp, "Production Sequence #: %d\n", prod.count);
fprintf(fp, "Consumption Sequence #: %d\n", consCount1);
}
else
{
get(&q2);
consCount2++;
fputs("Thread ID: 2\n", fp);
fprintf(fp, "Product Type: %d\n", prod.productType);
fprintf(fp, "Production Sequence #: %d\n", prod.count);
fprintf(fp, "Consumption Sequence #: %d\n", consCount2);
}
}
fclose(fp);
}
// https://www.youtube.com/watch?v=oyX30WVuEos&t=196s
// Circular buffer
void initQ(queue *q, int size)
{
q->size = size;
q->values = malloc(sizeof(product) * q->size);
q->numEntries = 0;
q->head = NULL;
q->tail = NULL;
}
// Checks if the queue is empty
bool QEmpty(queue *q)
{
return (q->numEntries == 0);
}
// Checks if the queue is full
bool QFull(queue *q)
{
return (q->numEntries == q->size);
}
// Used for adding products to the queue
bool put(queue *q, product prod)
{
// If the queue is full we can not add to it
if (QFull(q))
{
return false;
}
// Add product to the end of the queue
q->values[q->tail] = prod;
q->numEntries++;
// Move index of the tail
q->tail = (q->tail + 1);
// If index goes out of bounds set back to 0
if (q->tail >= q->size)
{
q->tail = 0;
}
return true;
}
// Used for removing products for the queue
product get(queue *q)
{
product result;
// If the queue is empty we can not dequeue anymore
if (QEmpty(q))
{
perror("Error on dequeue");
}
// Remove from the head of the queue
result = q->values[q->head];
q->head = (q->head + 1) & q->size;
q->numEntries--;
return result;
}
I suggest to revise the code to make it more readable since now it's quite hard to understand.
Here I point out some issues of your code that lead to errors:
if condition if (pidN = fork() == 0) {...}
you should fork() first and then check the pid:
int pidN = fork();
if (pidN == 0) {...}
fprintf() function fprintf("Thread ID: %d\n", prodType);
either write the function fputs or fprintf:
fputs("Thread ID: \n", fp);
or
fprintf(fp, "Thread ID: %d\n", prod.productType);
Parameter of the fprintf() function: pay attention to the variable you're passing since prodType does not exist.
I have a parent thread which creates child threads A,B,C,D,E,F. Each of these child threads runs a different disk scheduling algorithm and prints the result simultaneously. The task is to block these child threads while the parent thread waits for the user to input a file name, from which the disk scheduling data is parsed and read in order to be used in the disk scheduling algorithms for the child threads.
Currently my program first takes the user input before the creation of the child threads and therefor there is no need to block however my task is to block them.
#define N 71
typedef struct
{
int totalCylinders;
int cylindersInReqQueue;
int currentPos;
int prevDiskRequest;
int *requestQueueArr;
char id;
char *filename;
} disk_data;
sem_t semaphore;
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex;
void *runner(void *args);
void runscheduler(char name, disk_data data);
void *runner(void *args)
{
disk_data data = *(disk_data*)args;
char threadName = data.id;
pthread_mutex_lock(&mutex);
while(strlen(data.filename) == 0)
{
printf("IT REACHED THIS> GOING OUT");
pthread_cond_wait(&cond1, &mutex);
}
printf("Hello from thread %u I am %c\n", (int)pthread_self(),threadName);
runscheduler(threadName,data);
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void runscheduler(char name, disk_data data)
{
switch(name)
{
case 'A' :
firstComeFirstServe(data.cylindersInReqQueue, data.currentPos, data.requestQueueArr);
break;
case 'B' :
shortestSeekTimeFirst(data.totalCylinders, data.cylindersInReqQueue, data.currentPos, data.requestQueueArr);
break;
case 'C' :
scan(data.totalCylinders, data.currentPos, data.prevDiskRequest, data.cylindersInReqQueue, data.requestQueueArr);
break;
case 'D' :
cScan(data.totalCylinders, data.currentPos, data.prevDiskRequest, data.cylindersInReqQueue, data.requestQueueArr);
break;
case 'E' :
look(data.totalCylinders,data.currentPos,data.prevDiskRequest,data.cylindersInReqQueue,data.requestQueueArr);
break;
case 'F' :
cLook(data.totalCylinders,data.currentPos,data.prevDiskRequest,data.cylindersInReqQueue,data.requestQueueArr);
break;
default :
printf("Invalid grade\n" );
}
}
int main(int argc, char*argv[])
{
disk_data dd;
pthread_t tid[N];
int* res;
char *input;
int i,ret;
dd.cylindersInReqQueue =0;
dd.requestQueueArr = (int *) malloc(dd.cylindersInReqQueue * sizeof(int));
pthread_mutex_init(&mutex, NULL);
printf("***Disk Scheduler Simulation***");
input = readAndParse(&dd.totalCylinders, &dd.cylindersInReqQueue, &dd.currentPos, &dd.prevDiskRequest, &dd.requestQueueArr);
dd.filename = input;
for(i = 65; i < N; i++)
{
dd.id = (char)i;
ret = pthread_create(&tid[i], NULL, &runner, &dd);
if(ret != 0)
{
perror("Error: pthread_create() failed\n");
}
sleep(1);
printf ("Thread %c is created\n", i);
}
for(i = 65; i < N; i++)
{
if (pthread_join(tid[i], (void **) &res) != 0)
{
perror("Failed to join thread");
}
printf ("Thread %c has terminated\n", i);
}
pthread_mutex_destroy(&mutex);
printf ("All threads are now finished\n");
pthread_exit(NULL);
return 0;
}
I have the following program:
#include <stdio.h>
#include <sys/types.h>
#define MAX_COUNT 100
void ChildProcess(void);
void ParentProcess(void);
void main(void)
{
pid_t pid;
pid = fork();
if (pid == 0)
ChildProcess();
else
ParentProcess();
}
void ChildProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf(" This line is from child, value = %d\n", i);
printf(" *** Child process is done ***\n");
}
void ParentProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf("This line is from parent, value = %d\n", i);
printf("*** Parent is done ***\n");
}
I have to modify it in a way that both the parent and the child print stored data from the shared memory in the following way:
Create and initialize the shared memory in the parent.
Fill the shared memory with 5 integer numbers. (I should allocate enough shared memory to store the 5 ints.)
Fork from the parent to the child.
If fork is successful, then the child process must print the values stored in the shared memory as shown in the expected output where N1, N2, N3, N4, N5 are the numbers found in the shared memory.
Expected output
What I did in the ParentProcess function is the following:
void ParentProcess(void)
{
int i;
for (i = 1; i <= MAX_COUNT; i++)
printf("This line is from parent, value = %d\n", i);
printf("*** Parent is done ***\n");
int localVar = 0;
int* p = (int*) malloc(2);
pid_t childPID = fork();
*p = 0;
if (childPID >= 0)
{
printf("\nChild process has started\n");
if (childPID == 0)
{
localVar++;
globalVar++;
printf("Child process has found the following data %d,", *p);
*p = 70;
printf( " %d,", *p);
*p = 66;
printf(" %d,", *p);
*p = 51;
printf(" %d,", *p);
*p = 90;
printf(" %d in shared memory\n",*p);
printf("Child is existing\n\n");
}
}
}
And now I realize that I did it completely wrong but I have no idea how to fix that. I suppose I have to use shmget to create the shared memory, but then what? How do I store values in it?
If you find that you cannot help me with this or it is too long, please share sources where I can learn more about C programming in Linux, particularly regarding the usage of shared memory. Thank you in advance
It may be better to make it clear what you want to do first because as far as I read your code you call fork() twice in your code (once in main() function and once in ParentProcess() function)
So I write general solution for parent/child shared memory. There are several ways to achieve shared memory but this is one example which is modified version of the code here
How to use shared memory with Linux in C
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
void *create_shared_memory(size_t size)
{
int protection = PROT_READ | PROT_WRITE;
int visibility = MAP_SHARED | MAP_ANONYMOUS;
return mmap(NULL, size, protection, visibility, -1, 0);
}
int main()
{
// Allocate 4 ints
void *shmem = create_shared_memory(sizeof(int)*4);
if( shmem == NULL ){
fprintf(stderr, "Failed to create shared memory\n");
return -1;
}
// Initialize 4 ints
((int*)shmem)[0] = 10;
((int*)shmem)[1] = 100;
((int*)shmem)[2] = 1000;
((int*)shmem)[3] = 10000;
int pid = fork();
if (pid == 0)
{
// Print 4 ints in child
printf("Child reading int 0: %d\n", ((int*)shmem)[0]);
printf("Child reading int 1: %d\n", ((int*)shmem)[1]);
printf("Child reading int 2: %d\n", ((int*)shmem)[2]);
printf("Child reading int 3: %d\n", ((int*)shmem)[3]);
printf("Child end\n");
}
else
{
printf("Parent waiting for child ends...\n");
waitpid(pid, NULL, 0);
printf("Parent ends\n");
}
int ret = munmap(shmem, sizeof(int)*4);
if( ret != 0 ){
fprintf(stderr, "Failed to unmap shared memory\n");
return -1;
}
return 0;
}
I've written a small piece of c code which you might find helpful:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define NUM_INTS 5
int main(int argc, char *argv[])
{
key_t key = (key_t) 123456;
int shmgetrc, semgetrc;
struct shmid_ds ds;
int *shared_values;
int i;
struct sembuf sops[2];
int semid;
sops[0].sem_num = 0; /* Operate on semaphore 0 */
sops[0].sem_op = 0; /* Wait for value to equal 0 */
sops[0].sem_flg = 0;
sops[1].sem_num = 0; /* Operate on semaphore 0 */
sops[1].sem_op = 1; /* Increment value by one */
sops[1].sem_flg = 0;
/* create SHM segment */
shmgetrc = shmget(key, NUM_INTS * sizeof(int), IPC_CREAT | IPC_EXCL | 0x180);
if (shmgetrc < 0) {
perror("shmget failed...");
exit(1);
}
/* retrieve the address of the segment */
shared_values = (int *) shmat(shmgetrc, NULL, 0);
/* create a semaphore */
semgetrc = semget(key, 1, IPC_CREAT | IPC_EXCL | 0x180);
if (semgetrc < 0) {
perror("semget failed...");
exit(1);
}
/* lock the semaphore */
if (semop(semgetrc, sops, 2) == -1) {
perror("semop lock failed ...");
exit(1);
}
/* fill it with values */
for (i = 0; i < NUM_INTS; ++i) {
shared_values[i] = i;
}
/* unlock the semaphore */
sops[0].sem_op = -1;
if (semop(semgetrc, sops, 1) == -1) {
perror("semop release failed ...");
exit(1);
}
/* here something else could happen */
sleep(60);
/* lock the semaphore */
sops[0].sem_op = 0;
if (semop(semgetrc, sops, 2) == -1) {
perror("semop lock failed ...");
exit(1);
}
/* print values */
for (i = 0; i < NUM_INTS; ++i) {
printf("%d ", shared_values[i]);
}
printf("\n");
/* unlock the semaphore */
sops[0].sem_op = -1;
if (semop(semgetrc, sops, 1) == -1) {
perror("semop release failed ...");
exit(1);
}
/* remove the semaphore */
if (semctl(semgetrc, semgetrc, IPC_RMID) < 0) {
perror("semctl failed ...");
exit(1);
}
/* remove shm segment again */
if (shmctl(shmgetrc, IPC_RMID, &ds) < 0) {
perror("shmctl failed ...");
exit(1);
}
exit(0);
}
It was not my intention to write the most beautiful code ever written, just an example that shows:
how to create a shm segment
how to retrieve the address and to use it
how to remove it
Additionally, I've used a semaphore to protect the access.
Contrary to the other answer, I've used the ipc interface, not mmap().
I've got my code down for a dining philosopher problem, using shared memory. The issue I'm encountering is that 3 of 5 philosophers are eating which shouldn't be happening. Where am I going wrong in my code?
Updated: still not working right. Philosophers seem to not be going through one of the states
#include <stdio.h> // needed for printf, sprintf, ...
#include <stdlib.h> // needed for exit()
#include <unistd.h> // needed for sleep, fork, waitpid, _exit, ftruncate
#include <sys/wait.h> // needed for waitpid
#include <fcntl.h> // For O_* constants
#include <sys/mman.h> // needed for mmap, munmap and associated constants
#include <semaphore.h>
void philosopher(int i);
int parent(void);
void take_forks(int i);
void put_forks(int i);
void test (int i);
void think(int i);
void eat(int i);
#define N 5 /* number of philosophers */
#define THINKING 0 /* philosopher is thinking */
#define HUNGRY 1 /* philosopher is trying to get for ks */
#define EATING 2 /* philosopher is eating */
#define FINISH 3
#define LEFT (arga+4)%N
#define RIGHT (arga+1)%N
struct shared_memory {
int k;
int state[N];
sem_t s[N];
sem_t mutex;
};
struct shared_memory *shared;
int fd_shm, fd_log;
int main(void) {
if ((fd_shm = shm_open ("/test", O_RDWR | O_CREAT, 0660)) == -1)
printf("error");
if (ftruncate (fd_shm, sizeof (struct shared_memory)) == -1)
printf("error");
if ((shared = mmap (NULL, sizeof (struct shared_memory), PROT_READ | PROT_WRITE, MAP_SHARED,fd_shm, 0)) == MAP_FAILED)
printf("error");
// Initialize the shared memory
shared -> k = 0;
for (int i=0; i<N;i++){
shared -> state[i] = 0;
sem_init(&shared->s[i],0,1);
}
sem_init(&shared->mutex,1,1);
pid_t pids[N];
// At the beginning every philosopher is thinking
for (int l = 0; l < N; l++){
shared ->state[l]=THINKING;
}
printf("Start");
for(int j=0; j< N; j++){
if((pids[j] = fork()) < 0){
printf("failed");
perror("fork");
}else if (pids[j] == 0 ){
int pid = getpid();
printf("pids[%d] = %d\n",j,pid);
philosopher(j);
exit(0);
}
}
parent();
for (int m=0; m<N;m++){
waitpid(pids[m],NULL,0);
}
printf("This is final k %d\n",shared->k);
if (munmap(shared, sizeof(struct shared_memory)) == -1) {
printf("Function munmap() failed\n");
exit(-1);
}
if ((shm_unlink("/test")) == -1){
printf("Function shm_unlink() failed\n");
exit(-1);
}
return EXIT_SUCCESS;
}
void philosopher(int arga) {
//int count =0;
//while(count<5){
while(1){
//sleep(1);
//think(i);
take_forks(arga);
sleep(2);
//eat(i);
//sleep(1);
put_forks(arga);
//count++;
}
shared->state[arga] = FINISH;
}
void take_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga take_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutex */
shared->state[arga] = HUNGRY; /* record fact that philosopher i is hungry */
//while (shared->state[i] == HUNGRY){
test(arga); /* try to acquire 2 forks */
sem_post(&shared->mutex); /* exit critical region, up mutex */
//sem_wait(&shared->s[arga]); /* block if forks were not acquired, down philosopher*/
//}
//sleep(1);
}
void put_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga put_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutes */
//test(LEFT); /* see if left neighbor can now eat */
//test(RIGHT); /* see if right neighbor can now eat */
shared->state[arga] = THINKING; /* philosopher has finished eating */
sem_post(&shared->mutex); /* exit critical region, up mutex */
}
void test(int arga) /* i: philosopher number, from 0 to N−1 */
{
sem_wait(&shared->s[LEFT]);
sem_wait(&shared->s[RIGHT]);
shared->state[arga]= EATING;
sleep(1);
sem_post(&shared->s[RIGHT]);
sem_post(&shared->s[LEFT]);
//if (shared->state[arga] == HUNGRY && shared->state[LEFT] != EATING && shared->state[RIGHT] != EATING)
//{
//printf("Philosopher: %d (i+N-1)%N - %d", i, ((i+N-1)%N));
//shared->state[arga] = EATING;
//sleep(2);
//sem_post(&shared->s[arga]); //Up philosopher
//}
}
void think(int arga){
//printf("I am philosopher %d i am thinking\n", i);
sleep(2);
}
void eat(int arga){
//printf("I am philosopher %d i am eating\n", i);
sleep(3);
}
int parent(void){
puts("This is the Parent Process");
int philosopherState;
char* philprint;
int count=0;
int c;
while (1){
sleep(1);
//sem_wait(&shared->mutex);
for(int o = 0; o<N;o++ ){
/*philosopherState = shared->state[o];
if (philosopherState == 0) {
philprint = "Thinking";
}else if(philosopherState == 1){
philprint = "Eating";
}else if(philosopherState == 2){
philprint = "Hungry";
}else if(philosopherState == 3){
philprint = "Gone";
count++;
}*/
sem_getvalue(&shared->s[o], &c);
//printf("P%d %s \t",o, philprint);
if (c==0){
printf("P%d Thinking\t",o);
}
else if(c==1){
printf("P%d Eating\t",o);
}
else if (c==2){
printf("P%d Hungry\t",o);
}
else if (c==3){
printf("P%d Gone\t",o);
}
if (count >4){
break;
}
}
//sem_post(&shared->mutex);
printf("\n");
}
return 0;
}
//while(count<5){
while(1){
//sleep(1);
//think(i);
take_forks(arga);
sleep(2);
//eat(i);
//sleep(1);
put_forks(arga);
//count++;
}
shared->state[arga] = FINISH;
}
void take_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga take_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutex */
shared->state[arga] = HUNGRY; /* record fact that philosopher i is hungry */
//while (shared->state[i] == HUNGRY){
test(arga); /* try to acquire 2 forks */
sem_post(&shared->mutex); /* exit critical region, up mutex */
//sem_wait(&shared->s[arga]); /* block if for ks were not acquired, down philosopher*/
//}
//sleep(1);
}
void put_forks(int arga) /* i: philosopher number, from 0 to N−1 */
{
//printf("arga put_fork: %d\n", arga);
sem_wait(&shared->mutex); /* enter critical region, down mutes */
//test(LEFT); /* see if left neighbor can now eat */
//test(RIGHT); /* see if right neighbor can now eat */
shared->state[arga] = THINKING; /* philosopher has finished eating */
sem_post(&shared->mutex); /* exit critical region, up mutex */
}
void test(int arga) /* i: philosopher number, from 0 to N−1 */
{
sem_wait(&shared->s[LEFT]);
sem_wait(&shared->s[RIGHT]);
shared->state[arga]= EATING;
sleep(1);
sem_post(&shared->s[RIGHT]);
sem_post(&shared->s[LEFT]);
//if (shared->state[arga] == HUNGRY && shared->state[LEFT] != EATING && shared->state[RIGHT] != EATING)
//{
//printf("Philosopher: %d (i+N-1)%N - %d", i, ((i+N-1)%N));
//shared->state[arga] = EATING;
//sleep(2);
//sem_post(&shared->s[arga]); //Up philosopher
//}
}
void think(int arga){
//printf("I am philosopher %d i am thinking\n", i);
sleep(2);
}
void eat(int arga){
//printf("I am philosopher %d i am eating\n", i);
sleep(3);
}
int parent(void){
puts("This is the Parent Process");
int philosopherState;
char* philprint;
int count=0;
//int c;
while (1){
sleep(1);
for(int o = 0; o<N;o++ ){
philosopherState = shared->state[o];
if (philosopherState == 0) {
philprint = "Thinking";
}else if(philosopherState == 1){
philprint = "Eating";
}else if(philosopherState == 2){
philprint = "Hungry";
}else if(philosopherState == 3){
philprint = "Gone";
count++;
}
//sem_getvalue(&shared->s[o], &c);
printf("P%d %s \t",o, philprint);
//printf("P%d %s\t",o, c == 0 ? "Eating" : "Hungry");
if (count >4){
break;
}
}
printf("\n");
}
return 0;
}
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;
}