IPC - suggestions for synchronization of processes
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
IPC - suggestions for synchronization of processes
Hello,
I am writing an app and I need some suggestions as that what is the best way to inform another process of an event so it can continue to do work.
my app will fork a new process and i want the child process to wait until the parent process does some stuff after the fork( ). how can i make this work? whats the most common or best solution to do this kinda thing?
a condition variable is only for threads right?
a signal? setting an env variable? socket? pipe? writting to a file?
An env variable won't work at all. The environment of a process is set when it starts up and does not change during execution.
All other solutions you mentioned seem ok, but in my opinion a signal is the simplest and also most efficient one. You can even put your process to sleep until a signal arrives using pause().
The pause() library function causes the invoking process (or thread) to sleep until a signal is received that either terminates it or causes it to call a signal-catching function.
Semaphores are also a classic method of synchronization between threads or processes. There are at least two general classes of interproces communications; Sys V IPC, and Posix IPC. I believe both are supported on 2.4 and 2.6 Linux kernels. SysV IPC is for sure. My favorite tutorials on the subject are http://www.cs.cf.ac.uk/Dave/C/, and http://www.ecst.csuchico.edu/~beej/guide/ipc/.
Right, semaphores are a classical method for general purpose sincronization (e.g. access to shared data structures).
For this application in particular, maybe a signal is simpler.
Code:
#include <signal.h>
// #include all other things
void my_signal_handler(int signal_number) {
//It's ok to do nothing here
//you can also add code to handle the signal if you want
}
int main() {
//do stuff
signal(SIGUSR1, my_signal_handler);
//fork() etc
if (i_am_the_child_process) {
pause();
} else {
//do parent process stuff
kill(childpid, SIGUSR1); //this will cause the child to wake up
}
//do more stuff :)
}
Right, semaphores are a classical method for general purpose sincronization (e.g. access to shared data structures).
For this application in particular, maybe a signal is simpler.
Code:
#include <signal.h>
// #include all other things
void my_signal_handler(int signal_number) {
//It's ok to do nothing here
//you can also add code to handle the signal if you want
}
int main() {
//do stuff
signal(SIGUSR1, my_signal_handler);
//fork() etc
if (i_am_the_child_process) {
pause();
} else {
//do parent process stuff
kill(childpid, SIGUSR1); //this will cause the child to wake up
}
//do more stuff :)
}
is using the pause() really safe? what if the child process receives another signal and it continues to run without waiting for the signal that the parent process is supposed to send?
how can you make sure that the child waits for the signal SIGUSR1 from the parent?
Good observation, admiyo. If the child needs more info, then a signal won't be enough. This is a question for emge1 cause only he knows his app
The pause() function will wake up on other signals, but there is a simple workaround:
Code:
int wakeupflag; //global variable
void my_signal_handler(int signum) {
wakeupflag = 1;
}
int main() {
signal(SIGUSR1, my_signal_handler);
//fork etc
if (i_am_the_child) {
wakeupflag = 0;
while (!wakeupflag)
pause();
}
//blah blah blah
}
This way the child will only wakeup on SIGUSR1, wich won't be normally sent by other means. It is true that, as a user, you may send SIGUSR1 to the child process using the kill command, but that's close to a hacker's behavior. Is your app going to be distributed or is it just for yourself? In other words, are you concerned about this security stuff?
If the child needs more info from the parent, as admiyo noticed, I suggest adding file-reading code in the signal handler function instead of the wake-up flag. This way your program won't waste CPU cycles while the child waits for the file to be written by the parent. Or you may use a pipe instead of a signal, it's not quite complicated.
Good observation, admiyo. If the child needs more info, then a signal won't be enough. This is a question for emge1 cause only he knows his app
The pause() function will wake up on other signals, but there is a simple workaround:
This way the child will only wakeup on SIGUSR1, wich won't be normally sent by other means. It is true that, as a user, you may send SIGUSR1 to the child process using the kill command, but that's close to a hacker's behavior. Is your app going to be distributed or is it just for yourself? In other words, are you concerned about this security stuff?
If the child needs more info from the parent, as admiyo noticed, I suggest adding file-reading code in the signal handler function instead of the wake-up flag. This way your program won't waste CPU cycles while the child waits for the file to be written by the parent. Or you may use a pipe instead of a signal, it's not quite complicated.
The child doesn't need any other info from the parent, it just needs to be synchronized, so it doesn't run before the parent is doing some stuff.
However, i am concerned about this "hacker behavior" My app is going to be distributed, so yes I am concerned about security. what would be a better solution other than using the kill command? and why is it considered "hacker behavior?
If you use semaphores, you can make the keys to access the semaphore more obscure (not secure), as well as by using file-like permission levels. This can prevent malicious signals from disrupting your program. Semaphores were created to solve exactly this kind of problem.
--- rod.
You must not "assume" anything about the relative timing of the fork-operation nor the progress of the two processes once they have been launched.
If one process must wait until an operation has been completed by the other, then a semaphore is a good way to do it. It's initialized to a "not-signaled" state before the child process is launched. The parent process signals the semaphore when conditions are right for the child to be able to proceed.
Also explore the various interprocess communication (IPC) mechanisms that are available. If the two processes have a general need to exchange "messages" with one another during their normal, post-launch operations, then you can build that mechanism and simply stipulate that the child-process must wait for an "initialization completed" message from the parent.
You must not "assume" anything about the relative timing of the fork-operation nor the progress of the two processes once they have been launched.
If one process must wait until an operation has been completed by the other, then a semaphore is a good way to do it. It's initialized to a "not-signaled" state before the child process is launched. The parent process signals the semaphore when conditions are right for the child to be able to proceed.
Also explore the various interprocess communication (IPC) mechanisms that are available. If the two processes have a general need to exchange "messages" with one another during their normal, post-launch operations, then you can build that mechanism and simply stipulate that the child-process must wait for an "initialization completed" message from the parent.
ok thanks... how does this look... please provide any comments with things I don't need or things that can be done better.
thanks.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define SEMKEYPATH "/dev/null" /* Path used on ftok for semget key */
#define SEMKEYID 1 /* Id used on ftok for semget key */
#define NUMSEMS 1 /* Num of sems in created sem set */
union semun {
int val; /* used for SETVAL only */
struct semid_ds *buf; /* for IPC_STAT and IPC_SET */
ushort *array; /* used for GETALL and SETALL */
};
int main(void)
{
key_t semkey;
int rc, semid;
int status;
union semun arg;
struct sembuf operations[1];
/* Generate an IPC key for the semaphore set */
semkey = ftok(SEMKEYPATH, SEMKEYID);
if ( semkey == (key_t)-1 ){
printf("ftok() for sem failed\n");
return -1;
}
/* Create a semaphore set using the IPC key. The number of */
/* semaphores in the set is one. If a semaphore set already */
/* exists for the key, return an error. The specified permissions */
/* give everyone read/write access to the semaphore set. */
semid = semget( semkey, NUMSEMS, 0666 | IPC_CREAT );
if ( semid == -1 ){
perror("semget");
return -1;
}
/* initialize semaphore #0 to 1: */
arg.val = 1;
if (semctl(semid, 0, SETVAL, arg) == -1) {
perror("semctl");
return -1;
}
printf("Parent sem initialized to 1\n");
/* Set the structure passed into the semop() */
operations[0].sem_num = 0; /* Operate on the first sem */
operations[0].sem_op = -1; /* Decrement the semval by one */
operations[0].sem_flg = 0; /* Allow a wait to occur */
rc = semop( semid, operations, 1 );
if (rc == -1){
perror("semop");
return -1;
}
printf("Parent decremented sem to 0\n");
pid_t pid;
pid = fork();
if (pid < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid > 0) { /* Parent process */
printf("Parent Locked.\n");
printf("Parent does some stuff with pid %d.\n", pid);
operations[0].sem_op = 1; /* Increment the semval by 1 */
rc = semop( semid, operations, 1 );
if (rc == -1) {
perror("semop");
return -1;
}
printf("Parent Unlocked\n");
/* parent does other stuff */
waitpid(-1, &status, 0);
}
if (pid == 0) { /* Child process */
printf("Child Trying to lock...\n");
/* Set the structure passed into the semop() */
operations[0].sem_num = 0; /* Operate on the first sem */
operations[0].sem_op = -1; /* Decrement the semval by one */
operations[0].sem_flg = 0; /* Allow a wait to occur */
rc = semop( semid, operations, 1 );
if (rc == -1) {
perror("semop");
return -1;
}
printf("Child Locked.\n");
operations[0].sem_op = 1; /* Increment the semval by 1 */
rc = semop( semid, operations, 1 );
if (rc == -1) {
perror("semop");
return -1;
}
printf("Child Unlocked\n");
/* Clean up the environment by removing the semid structure */
rc = semctl( semid, 0, IPC_RMID, arg );
if (rc==-1)
{
printf("main: semctl() remove id failed\n");
return -1;
}
printf("Child can continue\n");
}
}
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.