Share POSIX semaphore among multiple processes - c

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
}

Related

Two pipe in C and ls | sort | grep r [duplicate]

This question already has answers here:
Pipe two or more shell commands in C using a loop
(1 answer)
Implementation of multiple pipes in C
(6 answers)
Combining two commands with a pipe
(1 answer)
Connecting n commands with pipes in a shell?
(2 answers)
Closed 18 days ago.
I need to create a program that execute in the shell this command with two pipes and three process: ls | sort | grep r. The code I have done is this:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#define WRITE 1
#define READ 0
int main(int argc, char** argv)
{
int fd1[2],fd2[2];
pid_t pid1,pid2;
if( (pid1 = fork()) < 0)
{
perror("fork");
exit(-1);
}
if( pipe(fd1) < 0)
{
perror("pipe 1");
exit(-1);
}
if( pipe(fd2) < 0)
{
perror("pipe 2");
exit(-1);
}
if( pid1 == 0 )
pid2 = fork();
if(pid1>0)
{
close(fd2[READ]);
close(fd2[WRITE]);
close(fd1[READ]);
dup2(fd1[WRITE],STDOUT_FILENO);
close(fd1[WRITE]);
execlp("ls","ls",NULL);
perror("ls");
exit(-1);
}
if(pid2>0)
{
close(fd1[WRITE]);
dup2(fd1[READ],STDIN_FILENO);
close(fd1[READ]);
close(fd2[READ]);
dup2(fd2[WRITE],STDOUT_FILENO);
close(fd2[WRITE]);
execlp("sort","sort",NULL);
perror("sort");
exit(-1);
}
if(pid2==0)
{
close(fd1[READ]);
close(fd1[WRITE]);
close(fd2[WRITE]);
dup2(fd2[READ],STDIN_FILENO);
close(fd2[READ]);
execlp("grep","grep","r",NULL);
perror("grep");
exit(-1);
}
}
Probably I have wrong with the communication with this two pipe because I'm learning how they works only today. So sorry If I wrong some important thing about pipe. I hope if somebody that can help me with this and explain what I wrong. Thanks.
You created the pipes after the 1st fork (but before the 2nd).
Which means that you called pipe 4 times, 2 times in each process that exist after the 1st fork.
So fd1 and fd2 have one set of values for main process (the one for which pid1>0, aka the one that executes ls), and another for the child and grandchild processes (the 2nd fork is done after the creation of the pipes, so no problem here: the two processes that executes sort and grep do share the same file descriptors).
So for the sort | grep part, no problem. The output of sort is fd2[1], while the input of grep is fd2[0], as you want, fd2 being the result of the same pipe call, that was executed before the 2nd fork, and therefore shared between those 2 processes.
But for the ls | sort part, what you are doing is exactly as if you did something like
if(fork()){
int fd[2];
pipe(fd);
close(fd[0]);
dup2(fd[1], 1);
printf("Hello\n");
exit(0);
}else{
int fd[2];
pipe(fd);
close(fd[1]);
dup2(fd[0], 0);
char s[100];
scanf("%s", s);
printf("Should be hello=%s\n", s);
exit(0);
}
Wouldn't work as expected. There is no relationship whatsoever between the fd of the two processes.
So you need to create the pipes before the fork.
At least, the pipes that you intend to share among the processes that will be created by this fork.
I think I know why you did this strange thing. Because of another caveat with 3 process pipe chain: we often see people creating all their pipe before forking twice, having problem making their code work. For another reason: they usually forget that their pipe exist in 3 process, and they need to close all those they don't use. Even in processes that have nothing to do with fd1, both end of fd1 must be closed.
Edit:
Another strange thing you did, is closing even fd1[WRITE] even in the process where you want to use it (just after dup2). You can't do that. It is not like after dup2 you can close the original pipe because you would have a copy, or something like that. It is a copy of a descriptor to the same file. If you close the file, it is closed for the copy too.
A rewrite of your code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#define WRITE 1
#define READ 0
int main(int argc, char** argv)
{
int fd1[2], fd2[2];
pid_t pid1,pid2;
if( pipe(fd1) < 0)
{
perror("pipe 1");
exit(-1);
}
if( (pid1 = fork()) < 0)
{
perror("fork");
exit(-1);
}
if( pid1 == 0 ){
if( pipe(fd2) < 0)
{
perror("pipe 2");
exit(-1);
}
pid2 = fork();
}
if(pid1>0)
{
// I need to close fd1[READ] that I don't use (and that "sort" will use)
// I must keep fd1[WRITE] that I use
// I leave fd2[READ/WRITE] alone, since that variable is unitialized here (I've called "pipe(fd2)" only in the case
// pid1==0 which it is not here)
close(fd1[READ]);
dup2(fd1[WRITE],STDOUT_FILENO);
execlp("ls","ls",NULL);
perror("ls");
exit(-1);
}
if(pid2>0)
{
// I need to read fd1, but not write it (it is ls that need to write it).
// So before doing anything, I close fd1[WRITE]. Must I must keep the other end, fd1[READ] open
close(fd1[WRITE]);
dup2(fd1[READ],STDIN_FILENO);
// Likewise, I need to write on fd2[WRITE], and have "grep" read on the other end.
// So I close fd2[READ] this side, and keep fd2[WRITE] open
close(fd2[READ]);
dup2(fd2[WRITE],STDOUT_FILENO);
execlp("sort","sort",NULL);
perror("sort");
exit(-1);
}
if(pid2==0)
{
// Last process. It needs to read fd2[READ], that I keep open, and don't need to write on fd2[WRITE] (that is "sort" job)
// so I close fd2[WRITE]
// I don't really case for fd1
// Situation is not exactly symetrical that for 1st process and fd2 tho. Because for 1st process, fd2 what not even initialized.
// While here, even if we don't need it, fd1 has been created by our grandfather. We shared it from our father, that shared it from its father
// So, since we use none of fd1, we need to close both.
close(fd1[READ]);
close(fd1[WRITE]);
close(fd2[WRITE]);
dup2(fd2[READ],STDIN_FILENO);
execlp("grep","grep","r",NULL);
perror("grep");
exit(-1);
}
}
Note that this is not the only solution. I could have created pipe(fd2) unconditionally before even the 1st fork, and then close both fd2[0] and fd2[1] in the "ls" process. That would have been ok too.
The points are:
If you want to write on a fd[1] in a process, and read what have been written, from another process, on fd[0], then those process must share the same fd values, issued by the same pipe call; so pragmatically, that means that pipe(fd) must have been called before the fork that separated those two processes
Don't close the fd?[?] that you use. Even if you use them only through another fd on which you dup2 the fd?[?].
Close any fd?[?] that exist in a process, that is that have been created by a pipe call (you must mentally keep tracks of which process have which fd) and you don't need.

Can a fork child determine whether it is a fork or a vfork?

Within the child process, is there any way that it determine whether it was launched as a fork with overlay memory, or a vfork with shared memory?
Basically, our logging engine needs to be much more careful (and not log some classes of activity) in vfork. In fork it needs to cooperate with the parent process in ways that it doesn't in vfork. We know how to do those two things, but not how to decide.
I know I could probably intercept the fork/vfork/clone calls, and store the fork/vfork/mapping status as a flag, but it would make life somewhat simpler if there was an API call the child could make to determine its own state.
Extra marks: Ideally I also need to pick up any places in libraries that have done a fork or vfork and then called back into our code. And how that can happen? At least one of the libraries we have offers a popen-like API where a client call-back is called from the fork child before the exec. Clearly the utility of that call-back is significantly restricted in vfork.
All code not specifically designed to work under vfork() doesn't work under vfork().
Technically, you can check if you're in a vfork() child by calling mmap() and checking if the memory mapping was inherited by the parent process under /proc. Do not write this code. It's a really bad idea and nobody should be using it. Really, the best way to tell if you're in a vfork() child or not is to be passed that information. But here comes the punchline. What are you going to do with it?
The things you can't do as a vfork() child include calling fprintf(), puts(), fopen(), or any other standard I/O function, nor malloc() for that matter. Unless the code is very carefully designed, you're best off not calling into your logging framework at all, and if it is carefully designed you don't need to know. A better design would most likely be log your intent before calling vfork() in the first place.
You ask in comments about a library calling fork() and then back into your code. That's already kind of bad. But no library should ever ever call vfork() and back into your code without being explicitly documented as doing so. vfork() is a constrained environment and calling things not expected to be in that environment really should not happen.
A simple solution could use pthread_atfork(). The callbacks registered with this service are triggered only upon fork(). So, the 3rd parameter of the function, which is called in the child process right after the fork, could update a global variable. The child can check the variable and if it is modified, then it has been forked:
/*
Simple program which demonstrates a solution to
make the child process know if it has been forked or vforked
*/
#include <pthread.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
pid_t forked;
void child_hdl(void)
{
forked = getpid();
}
int main(void)
{
pid_t pid;
pthread_atfork(0, 0, child_hdl);
pid = fork();
if (pid == 0) {
if (forked != 0) {
printf("1. It is a fork()\n");
}
exit(0);
}
// Father continues here
wait(NULL);
pid = vfork();
if (pid == 0) {
if (forked != 0) {
printf("2. It is a fork()\n");
}
_exit(0);
}
// Father continues here
wait(NULL);
return 0;
}
Build/execution:
$ gcc fork_or_vfork.c
$ ./a.out
1. It is a fork()
I came across kcmp today, which looks like it can answer the basic question - i.e. do two tids or pids share the same VM. If you know they represent forked parent/child pids, this can perhaps tell you if they are vfork()ed.
Of course if they are tids in the same process group then they will by definition share VM.
https://man7.org/linux/man-pages/man2/kcmp.2.html
int syscall(SYS_kcmp, pid_t pid1, pid_t pid2, int type,
unsigned long idx1, unsigned long idx2);
KCMP_VM
Check whether the processes share the same address space.
The arguments idx1 and idx2 are ignored. See the
discussion of the CLONE_VM flag in clone(2).
If you were created by vfork, your parent will be waiting for you to terminate. Otherwise, it's still running. Here's some very ugly code:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
void doCheck()
{
char buf[512];
sprintf(buf, "/proc/%d/wchan", (int) getppid());
int j = open(buf, O_RDONLY);
if (j < 0) printf("No open!\n");
int k = read(j, buf, 500);
if (k <= 0) printf("k=%d\n", k);
close(j);
buf[k] = 0;
char *ptr = strstr(buf, "vfork");
if (ptr != NULL)
printf("I am the vfork child!\n");
else
printf("I am the fork child!\n");
}
int main()
{
if (fork() == 0)
{
doCheck();
_exit(0);
}
sleep(1);
if (vfork() == 0)
{
doCheck();
_exit(0);
}
sleep(1);
}
This is not perfect, the parent might be waiting for a subsequent vfork call to complete.

Synchronization between childs and parent processes c

im trying to implement this:
Make a C multi-process program that does the following:
A process P generates two child processes P1 and P2. The two sons P1 and P2 perform an indeterminate cycle in which generate, each second, a random integer between 0 and 100. With each draw, the children communicate the numbers generated by the parent P process which provides for adding them, printing them on the screen and storing them in one file. Process P1 must handle the SIGINT interrupt signal. In particular, at the arrival of this signal P1 must display the warning message "P1 process busy!". The program is terminated by the parent P process when it verifies that the sum of the numbers, which it has received from the child processes, assumes the value 100.
Now, I need some help with the synchronization between childs and parent. Im trying to use semaphores but it looks like impossible. what can i use to synchronize them? signals? how?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <semaphore.h>
#include <fcntl.h>
#define READ 0
#define WRITE 1
void handler(int sig){
printf("process 1 is busy\n");
}
void codeprocess1(int pd[], sem_t *sem1){
int i = 0;
int numgenerated;
while( i = 0){
signal(SIGUSR1, handler);
numgenerated = rand()%101;
close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(sem1);
}
}
void codeprocess2(int pd[], sem_t *sem2){
int i = 0;
int numgenerated;
while( i = 0){
numgenerated = rand()%101;
close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(sem2);
}
}
int main(){
pid_t pid1, pid2;
int sum, numread1, numread2, pipe1[2], pipe2[2];
sem_t *sem2 = sem_open("semaph2", O_CREAT | O_EXCL, 1, 0);
sem_t *sem1 = sem_open("semaph1", O_CREAT | O_EXCL, 1, 0);
if(pipe(pipe1)<0){
exit(1);
}
if(pipe(pipe2)<0){
exit(1);
}
pid1 = fork();
switch(pid1){
case -1:
exit(1);
case 0:
codeprocess1(pipe1, sem1);
break;
default:
pid2= fork();
switch( pid2){
case -1:
exit(1);
case 0:
codeprocess2(pipe2, sem2);
break;
default:
while(sum!=1000){
close(pipe1[WRITE]);
read(pipe1[READ], &numread1, sizeof(int));
close(pipe2[WRITE]);
read(pipe2[READ], &numread2, sizeof(int));
sum = sum + numread1 + numread2;
printf("%d\n", sum);
sem_post(sem1);
sem_post(sem2);
}
kill(0, SIGKILL);
}
}
}
I'm reporting here the relevant part of the man page of sem_overview(7):
POSIX semaphores come in two forms: named semaphores and unnamed sema‐
phores.
Named semaphores
A named semaphore is identified by a name of the form /somename;
that is, a null-terminated string of up to NAME_MAX-4 (i.e.,
251) characters consisting of an initial slash, followed by one
or more characters, none of which are slashes. Two processes
can operate on the same named semaphore by passing the same name
to sem_open(3).
The sem_open(3) function creates a new named semaphore or opens
an existing named semaphore. After the semaphore has been
opened, it can be operated on using sem_post(3) and sem_wait(3).
When a process has finished using the semaphore, it can use
sem_close(3) to close the semaphore. When all processes have
finished using the semaphore, it can be removed from the system
using sem_unlink(3).
Unnamed semaphores (memory-based semaphores)
An unnamed semaphore does not have a name. Instead the sema‐
phore is placed in a region of memory that is shared between
multiple threads (a thread-shared semaphore) or processes (a
process-shared semaphore). A thread-shared semaphore is placed
in an area of memory shared between the threads of a process,
for example, a global variable. A process-shared semaphore must
be placed in a shared memory region (e.g., a System V shared
memory segment created using shmget(2), or a POSIX shared memory
object built created using shm_open(3)).
Before being used, an unnamed semaphore must be initialized
using sem_init(3). It can then be operated on using sem_post(3)
and sem_wait(3). When the semaphore is no longer required, and
before the memory in which it is located is deallocated, the
semaphore should be destroyed using sem_destroy(3).
You are trying to use unnamed semaphores in standard memory. But they are meant to synchronize threads only, not processes.
I suggest to use either named semaphores (that should be easier) or unnamed semaphores backed by shared memory (get it with shmget() or shm_open(), then use it with sem_init() - the parent and the forked processes must use the same shared memory segment to have access to the inter-process semaphore).
In fact, in your code sem1 and sem2, initialized in the main process, won't be propagated to the forked processes: they have independent memory regions and addresses, and cannot be shared.
After the edit, regarding the semaphores there are many problems:
the most logically wrong: you cannot pass the pointer of one process to another process: the addresses are not shared. Every process must independently open the semaphore and use it with his own handler.
while (i=0)... ouch, try compiling with -Wall.
You wasn't checking the return code of sem_open() it was failing with errno=13 (EACCESS)
You wasn't properly setting the permission of the semaphore... it's a (sort of) file. Note that once you crete it with the wrong permissions, it stays there and it won't be possible to create it again with the same name (until you reboot the system). You can see them with: ls -l /dev/shm, and eventually just remove them with rm.
You was requesting O_EXCL, that is, exclusive access to one process, that's not what you want. See man 2 open.
the name of the semaphore must begin with /, see man sem_overview
Here is the revised code, some comments in-line:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <semaphore.h>
#include <fcntl.h>
#include <errno.h>
#define READ 0
#define WRITE 1
#define SEM1_NAME "/semaph_1a"
#define SEM2_NAME "/semaph_2a"
void handler(int sig) {
printf("process 1 is busy\n");
}
void codeprocess1(int pd[]) {
int i = 0;
int numgenerated;
// each process must open the handle to the same named semaphore.
// they cannot share a local memory address.
sem_t *my_sem = sem_open(SEM1_NAME, O_CREAT , 0777, 0);
if (my_sem==SEM_FAILED) {
printf("semaphore creation failed, errno=%d\n", errno);
exit(1);
}
// the seed for the two children must be different or they will be generating the same
// sequence of random numbers.
srand(3333);
while(i == 0) {
signal(SIGUSR1, handler);
numgenerated = rand()%101;
// close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(my_sem);
}
}
void codeprocess2(int pd[]){
int i = 0;
int numgenerated;
sem_t *my_sem = sem_open(SEM2_NAME, O_CREAT, 0777, 0);
if (my_sem==SEM_FAILED) {
printf("semaphore creation failed, errno=%d\n", errno);
exit(1);
}
srand(1111);
while(i == 0) {
numgenerated = rand()%101;
// close(pd[READ]);
write(pd[WRITE], &numgenerated, sizeof(int));
sleep(1);
sem_wait(my_sem);
}
}
int main(){
pid_t pid1, pid2;
int sum, numread1, numread2, pipe1[2], pipe2[2];
// O_EXCL removed
// the mode flag must be set to 0777 for example, not "1".
// return value check added
sem_t *sem1 = sem_open(SEM1_NAME, O_CREAT , 0777, 0);
if (sem1==SEM_FAILED) {
printf("semaphore sem1 creation failed, errno=%d\n", errno);
exit(1);
}
sem_t *sem2 = sem_open(SEM2_NAME, O_CREAT, 0777, 0);
if (sem2==SEM_FAILED) {
printf("semaphore sem2 creation failed, errno=%d\n", errno);
exit(1);
}
if (pipe(pipe1) < 0 ) {
exit(1);
}
if (pipe(pipe2) < 0) {
exit(1);
}
pid1 = fork();
switch(pid1){
case -1:
exit(1);
case 0:
codeprocess1(pipe1);
break;
default:
pid2= fork();
switch( pid2) {
case -1:
exit(1);
case 0:
codeprocess2(pipe2);
break;
default:
// 100, not 1000
while (sum != 100) {
// all the "close()" calls are commented out
// close(pipe1[WRITE]);
read(pipe1[READ], &numread1, sizeof(int));
// close(pipe2[WRITE]);
read(pipe2[READ], &numread2, sizeof(int));
// sum must not be incremented
sum = numread1 + numread2;
printf("%d\n", sum);
sem_post(sem1);
sem_post(sem2);
}
kill(0, SIGKILL);
}
}
}
There is really a lot going on in your question.
As posted in the answer #Sigismondo, you are confusing multithreading with multiprocess programming. They have different method of communications.
To oversimplify threads share the same memory, so a thread can see for example values of global variables such as semaphores mutex and so on: if a thread modifies it, the other thread will be affected.
In multiprocessing when you fork(), a new process is generated with its own memory space. Right after the fork() variable values are almost the same (apart pid, ppid and so on) but they are in a different memory space: if you have a code block executed by only one process, modifying it will not affect the variables (the semaphores in your program) of the other process.
In your case: first of all if the children process do the same stuff (i.e. generate a random number) why do you have to different functions? Can't you do something like:
#include<stdlib.h>
int generateRand()
{
n = rand() % 100 + 1; //should be random in [1, 100]
}
HANDLING SIGNALS
Process P1 must handle the SIGINT interrupt signal. In particular, at
the arrival of this signal P1 must display the warning message "P1
process busy!". The program is terminated by the parent P process when
it verifies that the sum of the numbers, which it has received from
the child processes, assumes the value 100.
This is really unclear, in my opinion. The parent should catch the SIGINT signal. What should the children do? From what you say it seems they shouldn't catch that signal. In this case you must take a look at signal masks: basically you have to block the signal in the parent, the call the fork()s and then put back the original mask. Now you should go deeper but somehting like this (here)
sigset_t *parent_mask, *child_mask
//get the current mask
if (int res = sigprocmask (0, NULL, child_mask)<0)
printf("some error\n");
//make the mask block the signal
if (int res = sigaddset(child_mask, SIGINT)<0)
printf("some error in sigaddset \n");
// block the signal with the new mask
if (int res = sigprocmask (SIG_SETMASK, child_mask, parent_mask)<0)
printf("some error\n");
//do your forks: children will inherit the current mask and will not catch SIGINT
...
fork()
...
fork()
....
//set back the original mask so the parent catches SIGINT
if (int res = sigprocmask (SIG_SETMASK, parent_mask, NULL)<0)
printf("some error\n");
This answer of mine, although for multithreading should be a little clearer.
SIGNAL HANDLER
Why are you registering the signal handler in codeprocess1(int pd[])? I don't get it at all. And why SIGUSR1?
You should do it in the parent (before or after the fork()s shouldn't change since the signal is blocked for children: it depends if you want to have the user exit the program before starting the forks() or not: in the first case register the signal handler after the fork() otherwise put it at the beginning of main(). In both case you should do:
signal(SIGINT, handler);
Now the core to your program: to communicate your program you can use pipe() in a blocking way together with file descriptors: check here.
You need two file descriptors (one per child process and close the end (read/write) not used by the process).
Consider a single child process:
int p = fork();
int fd1[2]; //file descriptor for child1
int fd2[2]; //file descriptor for child2
if (p>0)//parent
{
close(fd1[1]);//close writing end
int n;
read(fd1[0], &n, sizeof(n));
//you might to call the other fork here and redo the same stuff
int p2 = fork();
if (p2>0)
{
close(fd2[1]);//close writing end
int n2;
read(fd2[0], &n2, sizeof(n2));
sum = n2+n1
if (sum==100 && exit = 1)
{
kill(p, SIGKILL);
kill(p2, SIGKILL);
}
}
}
else if(p==0)//child
{
close(fd1[0]);//close read end
int rand_n = generateRand();//or whaterver the name
wrote(fd1[1], &rand_n, sizeof(rand_n));
}
The exit condition is both based on the value of the sum (100) and the fact that CTRL+C has been pressed. The former is obvious in the code above. For the latter you can declare a global variable (I used exit) that if 0 CTRL+C has not been pressed, if 1 it has. This value is checked in the exit condition of the code above. Your handler will be responsible to write this variable:
//global variable here
int exit = 0;
void handler(int signo)
{
print("Parent busy doing stuff\n");
exit =1;
}
Note one thing exit is written by the parent since it is written ONLY in the handler which is called only by the parent and it is read in the part of the code executed only by the parent: the the children read its value it will be always 0 for them.
Being your question too general I tried to give some hints: there might be errors in my code since I haven't tried. You should study your own. If you will provide a minimal working example I will try to help.

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.

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)

Resources