c program deals with multithreading - c

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.

Related

Synchronizing two processes using POSIX named semaphore

I'm trying to write numbers (from 0-100 in incrementing order) on a file using two processes, where parent writes odd numbers and the child writes even numbers.
result on the file should look like this:
1 2 3 4 5 6 ...... 100
to do so i tried synchronizing using named semaphores
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/wait.h>
FILE *ptr; //file pointer
sem_t *s_even, *s_odd; //declaring two semaphores
const char *even = "even", *odd = "odd"; //semaphore names
void fileWR(); // function containing fork call
void parent(); //parent which writes in file odd numbers only
void child(); //child which writes in file even numbers only
int main(void) {
ptr = fopen("Semaphore.txt", "w+"); // openning the file
fileWR();
return 0;
}
// ***fileWR()***
void fileWR() {
sem_unlink(even); //unlink any exsiting semaphores
sem_unlink(odd);
if (ptr == NULL) {
fprintf(stderr, "ERROR!");
exit(-1);
}
// i'm not handeling if fork failed
if (fork() != 0) { // fork() process
int status;
//Parent
//prints odd numbers only
puts("####Parent#################");
parent();
wait(&status); // wait for child to terminate
} else {
//child
//prints even numbers only
puts("####Child#################");
child();
}
}
// ***parent()***
void parent() {
int i = 0;
//openning semaphore initialized at 0 since count starts 0
s_odd = sem_open(odd, O_CREAT | O_EXCL, 0644, 0);
if (s_odd == SEM_FAILED) {
perror("Parent : [sem_open] Failed\n");
return;
}
while (i <= 100) {
if (i % 2 != 0) { //id i is odd
if (sem_wait(s_odd) != 0)
perror("sem_wait"); //wait for child to finish writing in file
//critical section
//writing in file
fprintf(ptr, "i=%d ", i);
printf("i=%d ", i); //visualize what's being written on file
if (sem_post(s_even) != 0)
perror("sem_post"); //allow child to write
}
i++; //move to the next number
}
//After printing all odd number and done with file and semaphore
sem_unlink(odd);
sem_close(s_odd);
fclose(ptr);
}
// ***child()***
void child() {
//semaphore initialized to 1 since since count starts with O
s_even = sem_open(even, O_CREAT | O_EXCL, 0644, 1);
if (s_even == SEM_FAILED) {
perror("Child : [sem_open] Failed\n");
return;
}
int j = 0;
while (j <= 100) {
if (j % 2 == 0) { //if current number is even
if (sem_wait(s_even) != 0)
perror("sem_wait"); //waiting for parent to finish writing
//critical section
//write in the file (excepcted to execute first because s_even = 1
fprintf(ptr, "j= %d ", j);
printf("j=%d ", j); // visualize what's being written in the file
if (sem_post(s_odd))
perror("sem_post"); // allow parent to write
}
j++; //move to the next number
}
//After printing all even number and done with file and semaphore
sem_unlink(even);
sem_close(s_even);
fclose(ptr);
}
This is my approach to solve the problem.
When I execute the program
####Parent#################
####Child#################
and nothing seems to happen after.
I'm supposing there's something wrong with semaphore implementation?
(Edit: I've updated my code and the segmentation fault was fixed)

c program about multithreading

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;
}

Passing information between child and parent process - linux (without `pipe()`)

As part of my assignment, I have to implement child-parent processes.
"The parent process shall NOT wait for the child to exit but instead shall prints an element as soon as it arrives into the shared buffer ".
I know the case when the parent has to wait for child to end, but how to implement communication of message from child to parent in async way?
P.S. The exact Q is
Write a program whose main routine obtains two parameters n and d from the user, i.e. passed to your program when it was invoked from the shell. Your program shall then create a shared memory and a child process.
The child process should obtain the values of n and d (you have multiple choices on how to do that) and create an arithmetic sequence of length n, and whose first element is 0 and each subsequent element has the value of kd, where k is the element number (k= 0 to n-1).
The child process shall create the elements, one at a time and wait for a random interval of time (0 to 9.999 seconds) between generating elements of the sequence. As soon as an element is generated, the child places the element in the shared buffer by organizing it as described in slides 33-37 of lecture 4.
(e.g.: if n=5 and d=2, the sequence shall be 0,2,4,6,8)
The parent process shall NOT wait for the child to exit but instead shall prints an element as soon as it arrives into the shared buffer (again, in a manner similar to slides 33-37 of lecture 4)
Hint; use fflush() to ensure printf’s are printed immediately into the screen.
My code so far - gist
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
void printLab4(int n, int a, int *fibo)
{
int i;
for (i = 0; i < n; i++)
printf("%d -> %d\n", i, fibo[i]);
}
void computeLab4(int n, int a, int *fibo)
{
int i;
for (i = 0; i < n; i++)
{
int sleepSec = rand() % 10;
printf("sleeping for %d : ", sleepSec);
sleep(sleepSec);
fibo[i] = i * a;
// randomly sleeping for 0-10 secs
printf("Generated new element %d after %d seconds \n", fibo[i], sleepSec);
}
}
int main(int argc, char *argv[])
{
pid_t childPID;
int status;
int shm_fd;
int *shared_memory;
int msize; // the size (in bytes) of the shared memory segment
const char *name = "Lab_4";
int n, a;
if (argc != 3)
{
fprintf(stderr, "usage: %s <Lab4 Seq to be generated>\n", argv[0]);
return -1;
}
n = atoi(argv[1]);
a = atoi(argv[2]);
printf("%d \n", n);
printf("%d \n", a);
if (n < 0 || a < 0)
{
fprintf(stderr, "Illegal number: %s\n", argv[1]);
return -2;
}
// calculating the array size based on the number of terms being passed from child to parent
msize = (n + 2) * sizeof(int);
// open the memory
shm_fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG);
if (shm_fd < 0)
{
fprintf(stderr, "Error in shm_open()");
return -3;
}
printf("Created shared memory object %s\n", name);
// attach the shared memory segment
ftruncate(shm_fd, msize);
printf("shmat returned\n");
// allocating the shared memory
shared_memory = (int *)mmap(NULL, msize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (shared_memory == NULL)
{
fprintf(stderr, "Error in mmap()");
return -3;
}
printf("Shared memory segment allocated correctly (%d bytes).\n", msize);
shared_memory[0] = n;
shared_memory[1] = a;
childPID = fork();
if (childPID == -1)
{
fprintf(stderr, "Cannot proceed. fork() error");
return -4;
}
if (childPID == 0)
{
// then we're the child process
computeLab4(shared_memory[0], shared_memory[1], shared_memory + 1);
exit(0);
}
else
{
// parent will wait until the child finished
wait(&status);
// print the final results in the
printLab4(shared_memory[0], shared_memory[1], shared_memory + 1);
// now detach the shared memory segment
shm_unlink(name);
}
return 0;
}
Since you are acquiring the values from the command line at the time the program is invoked by the shell, when the parent calls fork(), the child will have access to the same variables. There is no need to "pass" the values from parent to child.
When the child creates the elements, I assume the parent is reading the elements from the shared memory. The "as soon as it arrives" is a somewhat dubious requirement unless you are on a parallel and real-time system. However, simulating that requirement can be achieved with a busy wait loop of the parent checking to see if the shared memory has acquired new data.
In order to not starve the operating system of CPU cycles while the parent is in the busy wait loop, the parent can call sched_yield() between check iterations, which behaves like a sleep that instantly wakes up.
The shared memory between parent and child can be treated as some kind of queue, and the busy wait of the parent is checking if the queue is non-empty, and if so, processes queue elements until it is empty, at which point it busy waits again.
for (;;) {
if (q_is_empty(q)) {
sched_yield();
continue;
}
int v = q_dequeue(q);
process(v);
}
Instead of sched_yield(), you could use usleep() or nanosleep() with a value of 1.
The child is of course adding elements to the queue, following the stipulations of the assignment.
for (;;) {
if (q_is_full(q)) {
sched_yield();
continue;
}
v = next_value_in_sequence_after_delay();
q_enqueue(v);
}
You may want to add an indication (such as enqueueing -1) that the child is done. The child can then exit, and the parent can know it is safe to reap the child.
The full check and empty check can logically be viewed as part of the enqueue and dequeue operations themselves. So, a possible implementation may be:
void q_enqueue(struct queue_type *q, int v) {
while (q_is_full(q)) sched_yield();
q->q[q->tail % Q_MAX_ELEM] = v;
q->tail += 1;
}
int q_dequeue(struct queue_type *q) {
while (q_is_empty(q)) sched_yield();
int v = q->q[q->head % Q_MAX_ELEM];
q->head += 1;
return v;
}
And then the parent and child functions might look like:
void parent(struct queue_type *q) {
for (;;) {
int v = q_dequeue(q);
if (v == -1) break;
printf("|%d", v);
fflush(stdout);
}
printf("|done!\n");
}
void child(struct queue_type *q, int n, int d) {
int v = 0;
for (;;) {
if (v == -1) break;
useconds_t t = rand() % 10000;
usleep(t * 1000);
v = next_value(n, d, v);
q_enqueue(q, v);
}
}
Below is the rest of the queue implementation I tested with, but you may want to research lock-free queues to see how you might implement single consumer / single producer queues without the need for traditional critical section protection.
#define Q_MAX_ELEM 1
struct queue_type {
volatile uint32_t head;
volatile uint32_t tail;
volatile int q[Q_MAX_ELEM];
};
void q_init(struct queue_type *q) {
static const struct queue_type q_zero;
*q = q_zero;
}
bool q_is_empty(struct queue_type *q) {
uint32_t tail = q->tail;
return q->head == tail;
}
bool q_is_full(struct queue_type *q) {
uint32_t head = q->head;
return (q->tail - head) == Q_MAX_ELEM;
}
Try it online!
The typical way to do this would be to create a pair of pipes shared between the child and parent, with the POSIX pipe() function. The Linux manual page even contains an example: https://www.man7.org/linux/man-pages/man2/pipe.2.html

How do I print stored data from the shared memory?

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().

Segmentation Fault in C producer/consumer using messagequeue

I am doing an assignment that implements the producer / consumer problem using a UNIX message queue as the data structure shared by a single producer and three consumers. The program I am creating is supposed to create a child process and the child process will in turn create three threads. The parent process is to be the producer and the three threads will be the consumers. The number of items, N, that are to be produced will be provided to the program via the command line. After spawning the child process the parent will enter an N-iteration loop. In each iteration of the loop the parent will do the following:
1) Generate a random number, R, in the range of 0-999.
2) Send a message containing R.
3) Add R to a running total of all values produced.
4) Display the string “Producer produced a R”.
5) Put the producer to sleep for 0-1 seconds using sleep(rand()%2).
After the N iterations have completed display the string "Total produced = XXXX” (where XXXX is the sum of all R values produced) and wait for the child to terminate. It is the parent’s responsibility to create and destroy the queue.
The child process will create three consumer threads, 0, 1 and 2. Each thread will enter an N/3 iteration loop. In each iteration of the loop each consumer thread will do the following:
1) Read a message containing a value, C, consumed from the queue.
2) Add C to a running total maintained by each consumer thread.
3) Display the string “Consumer thread Z consumed a C” where Z is the thread number – 0,1 or 2.
4) Put the consumer thread to sleep for 1-3 seconds using sleep((rand()%3)+1)
After N/3 iterations display the string "Total consumed by consumer thread Z = YYYY” where YYYY is the sum of all N/3 values consumed.I am receiving a segmentation fault in the last iteration of the loop and I am not sure why. Can anyone help me with this issue?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <pthread.h>
#include <sys/sem.h>
#include <semaphore.h>
struct msgbuf {
long mtype;
int mnum;
};
int msqid;
unsigned long total;
pthread_mutex_t sem_id;
int init() {
srand (time(NULL));
msqid = msgget(IPC_PRIVATE, IPC_CREAT | 0600);
if (msqid == -1) { perror("msgget"); return EXIT_FAILURE; }
pthread_mutex_init(&sem_id, NULL);
total = 0;
return 0;
}
int producer() {
int R = rand() % 999;
struct msgbuf msg = {999, R};
if(msgsnd(msqid, &msg, sizeof(msg.mnum) + 1, 0) == -1) {
perror("msgsnd"); return -1; }
total += R;
return R;
}
void *consumer(int thread_num, int iteration) {
struct msgbuf msg;
int thread_total = 0;
while(iteration--) {
pthread_mutex_lock(&sem_id);
if (msgrcv(msqid, &msg, sizeof(msg.mnum) + 1, 0, 0) == -1)
perror("msgrcv");
thread_total += msg.mnum;
printf("Consumer thread %d consumed a %d\n", thread_num, msg.mnum);
pthread_mutex_unlock(&sem_id);
}
printf("Total consumed by consumer thread %d = %d\n", thread_num,
thread_total);
sleep((rand()%3)+1);
}
int main(int argc, char *argv[]) {
int N = argc > 1 ? atoi(argv[1]) : 10;
if (init() != 0) return EXIT_FAILURE;
for (int i=0;i<N;i++) {
int R = producer();
if(R == -1) return EXIT_FAILURE;
printf("Producer produced a %d\n", R);
sleep(rand()%2);
}
printf("Total produced = %lu\n", total);
pthread_t thread_nums[3];
for (int i=0; i<=4; i++) {
int iteration = i == 0 ? N/3 + (N%3) : N/3;
if(pthread_create(&thread_nums[i], NULL,
consumer(i, iteration), NULL) != 0) {
perror("pthread_create");
return EXIT_FAILURE;
}
}
for (int i=0;i<4;i++) pthread_join(thread_nums[i], NULL);
return 0;
}
Ok so in the main function, thread_nums has 3 "slots", where as the loop proceeding wants to go over 5 different "slots".
Also, the last loop accesses a "slot" which does not exist
Remember that an array of size [3] has only three positions. The last item is at index 2 (0,1,2), for a total of three elements.

Resources