Semaphore example in C - c

I am trying to make a simple semaphore example in C in which, having two while loops, will produce this outcome without threads, using two diferrent processes :
abcd
abcd
abcd
abcd
Since I cannot use pthreads, I tried to make the common signal() and wait() methods but for some reasons, I get an error in the wakeup call inside my signal method.
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
wait(sem_t *s)
{
s=s-1;
if (s<0)
block(); // add process to queue
}
signal(sem_t *s)
{
s=s+1;
if (s<=0)
wakeup(p); // remove process p from queue
}
init(sem_t *s , int v)
{
s=v;
}
void main(void)
{
int i;
// place semaphore in shared memory
sem_t *child_sem = mmap(NULL,sizeof(*child_sem),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
sem_t *parent_sem = mmap(NULL,sizeof(*parent_sem),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
init(child_sem, 1); // create child semaphore
init(parent_sem, 1); // create parent semaphore
if (fork())
{
for (i = 0; i < 10; i++)
{
if (wait(child_sem) < 0)
perror("sem_wait");
printf("ab");
if (signal(parent_sem) < 0)
perror("sem_post");
sleep(1); // required to maintain thread order
}
}
else
{
for (i = 0; i < 10; i++)
{ // parent starts waiting
if (wait(parent_sem) < 0)
perror("sem_wait");
printf("cd\n");
if (signal(child_sem) < 0)
perror("sem_post");
}
}
}
Output:
[Error] In function 'signal':
[Error] 'p' undeclared (first use in this function)
The thing is that how could I enter a process p inside the wakeup call?
Should I use a pid=fork() inside a method?
Should I use an extra argument in signal method but what would it be like? pid p ?
If I remove the p argument from wakeup, then variables like PROT_READ become undeclared for some reason.
P.S. The code is from this site.

I will not write the the whole thing but here is a better way to solve this.
Use 2 semaphores.
Run the first process when semaphore number 1 is high
Run the second process when semaphore number 2 is high
At the starting of the critical section of 1st process, make 2nd semaphore low so that the resource can not be used by the 2nd process
At the end of the critical section of the 1st process, make the 2nd semaphore = 1 and 1st semaphore = 0
Do exactly opposite for the second process, i.e., stating sem1 = 0, ending sem1 = 1, sem2 = 0.
This may solve the problem. Never use signal use sigaction instead.

Related

What child does not inherit semaphore adjustments from its parent (semop(2)) mean?

This line in the fork(doc) man got my attention:
The child does not inherit semaphore adjustments from its parent (semop(2)).
What does it mean?
This program(code below) would never print "End (child)" :
#define SVID_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char **argv) {
struct sembuf operation;
int semid = semget (getpid(), 1, 0666 | IPC_CREAT);
semctl (semid, 0, SETVAL, 1);
if (fork() == 0) {
sleep(1); // Let the father do semop()
operation.sem_num = 0;
operation.sem_op = -1;
operation.sem_flg = 0;
semop (semid, &operation, 1);
printf("End (child).\n");
exit(0);
}
operation.sem_num = 0;
operation.sem_op = -1;
operation.sem_flg = 0;
semop (semid, &operation, 1);
wait (NULL);
printf("The end.\n");
return 0;
}
In the first place, there are two independent semaphore subsystems: old-style System V semaphores and POSIX semaphores. Do not be confused by the fact that both are part of POSIX. The ones relevant to the question are System V semaphores.
The semop(2) syscall is the one used for manipulating values in a system V semaphore set. A process that modifies a semaphore set via this function can do so in a way that is automatically undone when the process exits, by including a particular flag (represented by SEM_UNDO) among the arguments. This causes a set of "semaphore adjustments" for that semaphore set to be associated with the process. It is these adjustments that are not inherited across a fork, and that makes sense because if they were inherited then the undo would be performed twice -- once when the child exits, and once when the parent exits.
POSIX semaphores are generally considered to provide a much better API, and generally they should be preferred over system V semaphores, but it's helpful to be aware of both.

memory synchronization

I have the function display.c :
/* DO NOT EDIT THIS FILE!!! */
#include <stdio.h>
#include <unistd.h>
#include "display.h"
void display(char *str)
{
char *p;
for (p=str; *p; p++)
{
write(1, p, 1);
usleep(100);
}
}
and display.h is:
/* DO NOT EDIT THIS FILE!!! */
#ifndef __CEID_OS_DISPLAY_H__
#define __CEID_OS_DISPLAY_H__
void display(char *);
#endif
My task is to use pthreads in order to have the following output:
abcd
abcd
abcd
..
..
Note that I must not edit the file display.c or the file display.c. I have to use mutexes in order to succeed the output that is shown above.
The following block of code is my closest attempt to finally reach the result I want:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <pthread.h>
#include "display.h"
pthread_t mythread1;
pthread_t mythread2;
pthread_mutex_t m1, m2;
void *ab(void *arg)
{
pthread_mutex_lock(&m1);
display("ab");
pthread_mutex_unlock(&m1);
}
void *cd(void *arg)
{
pthread_mutex_lock(&m1);
display("cd\n");
pthread_mutex_unlock(&m1);
}
int main(int argc, char *argv[])
{
pthread_mutex_init(&m1, NULL);
pthread_mutex_init(&m2, NULL);
int i;
for(i=0;i<10;i++)
{
pthread_create(&mythread1, NULL, ab, NULL);
pthread_create(&mythread2, NULL, cd, NULL);
}
pthread_join(mythread1, NULL);
pthread_join(mythread2, NULL);
pthread_mutex_destroy(&m1);
pthread_mutex_destroy(&m2);
return EXIT_SUCCESS;
}
The output of the code above is something like this:
abcd
abcd
abcd
abcd
ababcd
cd
abcd
abcd
abcd
abcd
As you can see "ab" and "cd\n" are never mixed but every time I run the code the output differs. I want to make sure that every time I run this code the output will be:
abcd
abcd
abcd
for ten times.
I am really stuck with this since I can't find any solution from the things I already know.
A mutex cannot (by itself) solve your problem. It can prevent your two threads from running concurrently, but it cannot force them to take turns.
You can do this with a condition variable in addition to the mutex, or with a pair of semaphores. Either way, the key is to maintain at all times a sense of which thread's turn it is.
Myself, I think the semaphore approach is easier to understand and code. Each semaphore is primarily associated with a different thread. That thread must lock the semaphore to proceed. When it finishes one iteration it unlocks the other semaphore to allow the other thread to proceed, and loops back to try to lock its own semaphore again (which it cannot yet do). The other thread works the same way, but with the semaphore roles reversed. Roughly, that would be:
sem_t sem1;
sem_t sem2;
// ...
void *thread1_do(void *arg) {
int result;
do {
result = sem_wait(&sem1);
// do something
result = sem_post(&sem2);
} while (!done);
}
void *thread2_do(void *arg) {
int result;
do {
result = sem_wait(&sem2);
// do something else
result = sem_post(&sem1);
} while (!done);
}
Semaphore initialization, error checking, etc. omitted for brevity.
Updated to add:
Since you now add that you must use mutexes (presumably in a non-trivial way) the next best way to go is to introduce a condition variable (to be used together with the mutex) and an ordinary shared variable to track which thread's turn it is. Each thread then waits on the condition variable to obtain the mutex, under protection of the mutex checks the shared variable to see whether it is its turn, and if so, proceeds. Roughly, that would be:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int whose_turn = 1;
// ...
void *thread1_do(void *arg) {
int result;
result = pthread_mutex_lock(&mutex);
while (1) {
if (whose_turn == 1) {
// do something
whose_turn = 2; // it is thread 2's turn next
}
// break from the loop if finished
result = pthread_cond_broadcast(&cond);
result = pthread_cond_wait(&cond, &mutex);
}
result = pthread_mutex_unlock(&mutex);
}
void *thread1_do(void *arg) {
int result;
result = pthread_mutex_lock(&mutex);
while (1) {
if (whose_turn == 2) {
// do something else
whose_turn = 1; // it is thread 1's turn next
}
// break from the loop if finished
result = pthread_cond_broadcast(&cond);
result = pthread_cond_wait(&cond, &mutex);
}
result = pthread_mutex_unlock(&mutex);
}
Error checking is again omitted for brevity.
Note in particular that when a thread waits on a condition variable, it releases the associated mutex. It reaquires the mutex before returning from the wait. Note also that each checks at each iteration whether it is its turn to proceed. This is necessary because spurious wakeups from waiting on a condition variable are possible.
You can use a conditional variable to take turns between threads:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int turn = 0;
void *ab(void *arg)
{
pthread_mutex_lock(&m1);
while (turn != 0)
pthread_cond_wait(&cond, &m1);
display("ab");
turn = 1;
pthread_mutex_unlock(&m1);
pthread_cond_signal(&cond);
}
void *cd(void *arg)
{
pthread_mutex_lock(&m1);
while (turn != 1)
pthread_cond_wait(&cond, &m1);
display("cd\n");
turn = 0;
pthread_mutex_unlock(&m1);
pthread_cond_signal(&cond);
}
Another problem is, you are joining with the last two pair of threads created in main() thread, which are not necessarily the ones get executed as last. If threads created early are not completed, then you are destroying the mutex m1 while it might be in use and exiting whole process.
Consider this approach to the issue:
for(i=0;i<10;i++)
{
ab();
cd();
}
This achieves your goals completely, given the shown code. The problem with your example is that you effectively prevent any synchronization and that seems to be your goal even!
Assuming that before the output, you actually want to do something useful which takes CPU time, the answer is that you will have to change the code of display(), which is simply not suitable for parallelization. Proper concurrent code is designed to work independent of other code, in particular it shouldn't compete for resources (locks) with other calls and it shouldn't rely on the order it finishes.
In summary, you can't learn much from this, it's a bad example. In order to improve the code (the one you don't want to change, but that's your problem), consider that the resource the different threads compete for is stdout. If they each wrote to their own buffer, you could create the threads, wait for them to finish and only then reorder their results for output.

Share POSIX semaphore among multiple processes

I need to create two child processes each of which calls execvp ater being forked, and the executables share POSIX semaphores between them.
Do I need to create a shared memory or just implement named semaphores?
I got two answers from the following links:
Do forked child processes use the same semaphore?
How to share semaphores between processes using shared memory
But I am confused about how to proceed in the implementation.
Do I need to create a shared memory or just implement named
semaphores?
Either approach will work. Pick one and go with it - though I personally prefer named semaphores because you don't have to deal with memory allocation and with setting up the shared memory segments. The interface for creating and using named semaphores is way more friendly, in my opinion.
With named semaphores, in your example scenario, here's what happens:
You create and initialize the semaphore in the parent process with sem_open(3). Give it a well-known name that the child processes will know; this name is used to find the semaphore in the system.
Close the semaphore in the parent, since it won't be using it.
Fork and execute
Unlink the semaphore with sem_unlink(3). This must be done exactly once; it doesn't really matter where (any process that has a reference to the semaphore object can do it). It is ok to unlink a semaphore if other processes still have it open: the semaphore is destroyed only when all other processes have closed it, but keep in mind that the name is removed immediately, so new processes won't be able to find and open the semaphore.
The child processes call sem_open(3) with the well-known name to find and obtain a reference to the semaphore. Once a process is done with the semaphore, you need to close it with sem_close(3).
Below is an example of what I just described. A parent process creates a named semaphore, and forks + executes 2 child processes, each of which finds and opens the semaphore, using it to synchronize between each other.
It assumes that the parent forks and executes the ./sem_chld binary. Keep in mind that a name for a semaphore must begin with a forward slash, followed by one or more characters that are not a slash (see man sem_overview). In this example, the semaphore's name is /semaphore_example.
Here's the code for the parent process:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#define SEM_NAME "/semaphore_example"
#define SEM_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
#define INITIAL_VALUE 1
#define CHILD_PROGRAM "./sem_chld"
int main(void) {
/* We initialize the semaphore counter to 1 (INITIAL_VALUE) */
sem_t *semaphore = sem_open(SEM_NAME, O_CREAT | O_EXCL, SEM_PERMS, INITIAL_VALUE);
if (semaphore == SEM_FAILED) {
perror("sem_open(3) error");
exit(EXIT_FAILURE);
}
/* Close the semaphore as we won't be using it in the parent process */
if (sem_close(semaphore) < 0) {
perror("sem_close(3) failed");
/* We ignore possible sem_unlink(3) errors here */
sem_unlink(SEM_NAME);
exit(EXIT_FAILURE);
}
pid_t pids[2];
size_t i;
for (i = 0; i < sizeof(pids)/sizeof(pids[0]); i++) {
if ((pids[i] = fork()) < 0) {
perror("fork(2) failed");
exit(EXIT_FAILURE);
}
if (pids[i] == 0) {
if (execl(CHILD_PROGRAM, CHILD_PROGRAM, NULL) < 0) {
perror("execl(2) failed");
exit(EXIT_FAILURE);
}
}
}
for (i = 0; i < sizeof(pids)/sizeof(pids[0]); i++)
if (waitpid(pids[i], NULL, 0) < 0)
perror("waitpid(2) failed");
if (sem_unlink(SEM_NAME) < 0)
perror("sem_unlink(3) failed");
return 0;
}
Note that sem_unlink(3) is called after both children terminate; although this is not required, if it was called before there would be a race condition between the parent process unlinking the semaphore and both child processes starting up and opening the semaphore. In general, though, you can unlink as soon as you know that all required processes have opened the semaphore and no new processes will need to find it.
Here's the code for sem_chld, it's just a small toy program to show the usage of a shared semaphore:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#define SEM_NAME "/semaphore_example"
#define ITERS 10
int main(void) {
sem_t *semaphore = sem_open(SEM_NAME, O_RDWR);
if (semaphore == SEM_FAILED) {
perror("sem_open(3) failed");
exit(EXIT_FAILURE);
}
int i;
for (i = 0; i < ITERS; i++) {
if (sem_wait(semaphore) < 0) {
perror("sem_wait(3) failed on child");
continue;
}
printf("PID %ld acquired semaphore\n", (long) getpid());
if (sem_post(semaphore) < 0) {
perror("sem_post(3) error on child");
}
sleep(1);
}
if (sem_close(semaphore) < 0)
perror("sem_close(3) failed");
return 0;
}
You can eliminate the need to keep the semaphore name synchronized between the two source files by defining it in a common header file and including it in the code for each program.
Note that error handling is not ideal in this example (it's merely illustrative), there is a lot of room for improvement. It's just there to make sure you don't forget to do proper error handling when you decide to change this example to suit your needs.
Shared memory approach will also work here, only thing here is parent process has to initialise the shared memory.
There seems one bug in this code instead of two child, parent function will fork 3 child process here. There should be break statement inside
if (pids[i] == 0) {
if (execl(CHILD_PROGRAM, CHILD_PROGRAM, NULL) < 0) {
perror("execl(2) failed");
exit(EXIT_FAILURE);
}
break; //this is required
}

Processes and semaphores

So i was experimenting on how to use fork and semaphores for a homework and it seems everytime i run the program fork always returns a number >0, while what i wanted was to first have several processes be made then be stopped using semaphores and then have some of them restart again.
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
int main(int argc,char *argv[])
{
int i,count;
count = 0;
pid_t *Pc;
Pc=(pid_t *) malloc((argc-2)*sizeof(pid_t));
sem_t *sem;
sem = (sem_t *) malloc((argc-2)*sizeof(sem_t));
for (i = 0; i <= argc-2; i++){
sem_init(&sem[i], 0, 0);
}
for (i =0; i<=argc-2; i++){
Pc[i] = fork();
if (Pc[i] == 0){
printf(" child");
sem_wait(&sem[i]);
printf("Experiment was a success!");
}
if (Pc[i]>0){
printf("Parent");
}
}
for (i =0; i<=argc-2; i++){
if (Pc[i] > 0)
count++;
}
for (i= 0; i<=3; i++){
if ( count == argc-2){
sem_post(&sem[i]);
}
}
}
nameofprogram 1 2
prints: Parent
Child
Parent
Child
You need to read the man page for sem_init(). The type of semaphore you are creating right now is not shared across processes. This requires a non-trivial change to your program, because you also need to set up shared memory. Refer to this question for a lengthy explanation of how to make your program work.
When a program calls fork, a new process is created with a new exact copy of the memory space. This mean that sem in your child process is not the same as sem in your parent process. So, when you call sem_post, you child process can not be notified of the change and get out of the wait function.
To solve this, you have different possibilities:
Create a shared memory which can be read by all your processes and create this semaphore in this shared memory, as already suggested.
Use named semaphores with sem_open. This kind of semaphore can be shared across different processes as it work like a file handle. This seems to be an easier way if you only need a shared semaphore (example here). You will have to generate a unique name for each semaphore in your array (may be only one semaphore on which you call sem_post multiple times would be enough for your use).
Keep your semaphores and use threads instead of processes (but I guess your homework is about processes so this may not be an option for you)

Need to access variables from child during SIGCHLD handler

I'm prefacing this by stating that it is a homework assignment and I'm stuck while writing the SIGCHLD handler. I need to access variables within the child process.
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define TEXT_LEN 10
#define NUM_RESCUE_PLOWS 4
#define NUM_VICTIMS_TO_RESCUE 40
/* PURPOSE: To keep trap of the number of victims that have been rescued.
*/
int numRescuedVictims = 0;
/* PURPOSE: To keep track of the process id's of the rescuing snow plows.
*/
pid_t plowPid[NUM_RESCUE_PLOWS];
/* PURPOSE: To note that at least one child plow has finished. Reports the
*process id and the number of victims rescued for each child plow.
*'sigNum' tells the signal number. No return value
*/
// You may want to define a SIGCHLD listener here
// It should have a loop that wait()s for children and
// and prints how many victims each has rescued.
void listenSIGCHLD(int sig)
{
int status;
pid_t pidWait;
while((pidWait = wait(&status)) > 0)
printf("Plow %d rescued %d victim(s)", plowId, numVictimsRescued);
}
/* PURPOSE: To handle being informed of a rescued victim. 'sigNum' tells
*signal number. No return value.
*/
// You may want to define a SIGUSR1 listener here
// It increments 'numRescuedVictims' and prints the total number rescued victims
void listenSIGUSR1(int sig)
{
numRescuedVictims += &numVictimsRescued;
printf("We've rescued %d victims!" numRescuedVictims);
}
/* PURPOSE: To make 'NUM_RESCUE_PLOWS' processes to run 'rescuingPlow' to
*rescue stuck victims, and then tell them to quit after all
*'NUM_VICTIMS_TO_RESCUE' victims have been rescued. Ignores parameters.
*Returns 'EXIT_SUCCESS' to OS.
*/
int main ()
{
// I. Applicability validity check:
// II. Rescue victims:
// II.A. Install 'SIGUSR1' handler:
signal(SIGUSR1, listenSIGUSR1);
// Install 'SIGUSR1' handler
// Install your SIGCHLD handler here
signal(SIGCHLD, listenSIGCHLD);
// II.B. Tell NUM_RESCUE_PLOWS plows to start rescuing the victims:
int i;
int myPid= getpid();
for (i = 0; i < NUM_RESCUE_PLOWS; i++)
{
// Do a fork() and save it in plowPid[i]
plowPid[i] = fork();
// If plowPid[i] is less than 0 then do:
if(plowPid[i] < 0)
{
fprintf(stderr,"Dude, your system is WAY to busy to play rescuer!\n");
return(EXIT_FAILURE);
}
// If plowPid[i] is equal to 0 then do:
else if(plowPid[i] == 0)
{
char pidText[TEXT_LEN];
char indexText[TEXT_LEN];
}
snprintf(pidText,TEXT_LEN,"%d",myPid);
snprintf(indexText,TEXT_LEN,"%d",i);
execl("./rescuingPlow","rescuingPlow",pidText,indexText,NULL);
fprintf(stderr,"Dude, somebody stole my plow!!\n");
return(EXIT_FAILURE);
}
// II.C. Wait until all victims have been rescued:
while (numRescuedVictims < NUM_VICTIMS_TO_RESCUE)
{
sleep(1);
printf("Searching for victims . . .\n");
}
// III. Finished:
// Loop to send SIGTERM to all NUM_RESCUE_PLOWS plow processes
for (int i = 0; i < NUM_RESCUE_PLOWS; i++)
{
kill(plowPid[i], SIGTERM);
}
int toSleep= NUM_RESCUE_PLOWS;
// sleep() can be interrupted by SIGCHLD. Whenever it is interrupted
// it returns the number of seconds that still remain on its alarm
// clock. Let's wait until it has slept its full amount incase it
// was prematured interrupted by SIGCHLD.
do
{
toSleep= sleep(toSleep);
}
while (toSleep > 0);
printf("Ready for the NEXT snow storm!\n");
return(EXIT_SUCCESS);
}
`
and here's what's going to end up being the spawned processes. Although I haven't worked through that yet.
/*
* rescuingPlow.c
*
* Compile with $ gcc rescuingPlow.c -o rescuingPlow
*/
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
/* PURPOSE: To keep track of the number of victims that this process
* rescued.
*/
int numVictimsRescued = 0;
/* PURPOSE: To return the number of victims rescued to the OS. 'sigNum'
* tells the signal number. No return value.
*/
// You may want to write a SIGTERM handling function
// that returns to the OS 'numVictimsRescued'.
/* PURPOSE: To rescue victims at random intervals and inform parent process
* by sending it SIGUSR1 until receiving SIGTERM. First parameter (after
* program name) tells parent's process id. Second parameter tells this
* plow's index.
*/
int main (int argc, char* argv[])
{
// I. Applicability validity check:
pid_t parentPID;
int plowId;
if (argc < 3)
{
fprintf(stderr,"USAGE: rescuingPlow <parentPID> <plowId>\n");
return(EXIT_FAILURE);
}
parentPID = atoi(argv[1]);
plowId = atoi(argv[2]);
// II. Rescuing victims until told to stop:
// II.A. Install signal handler:
// Install your SIGTERM handler here
srand(plowId); // Uniquely initialize random number generator so they act independently of each other
// II.B. Rescue victims:
// Write an endless loop that:
// (1) Does 'sleep((rand() % 6) + 1);'
// (2) Increments 'numVictimsRescued'
// (3) Does 'printf("Plow %d rescued %d victim(s)!\n",plowId,numVictimsRescued);'
// (4) Send 'SIGUSR1' to 'parentPID'
// III. Finished:
return(EXIT_SUCCESS);
}
I'm not completely sure where I'm going with this or how to deal with that. I'm pretty confident I can deal with most of the other problems that exist.
Without using some IPC mechanics the child can only pass a value of 8 bits to the parent process.
Those 8 bits are send by the child as parameter to the call to exit() and receive by the parent by applying the macro WEXITSTATUS() to the value of status as returned by a successful call to wait() or waitpid(). Please see man 2 exit and man 2 wait for details.
If I remember correctly 8 bits are the minimum as defined by the standard. Some implementations might allow more bits.
Update:
Example on how to use wait():
int child_exit_code = -1;
int status = -1;
pid_t pid = wait(&status);
if (-1 != pid)
child_exit_code = WEXITSTATUS(status);
You can use shmget to allocate shared memory.
Use it before forking, and then the allocated memory will be accessible to both child and parent.
The child can store whatever it wants there, and the parent will read it.

Resources