LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 03-22-2007, 03:17 PM   #1
emge1
LQ Newbie
 
Registered: Sep 2006
Posts: 15

Rep: Reputation: 0
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?

thanks for the suggestions
 
Old 03-22-2007, 04:51 PM   #2
nacio
LQ Newbie
 
Registered: Mar 2007
Location: Italy
Distribution: Debian
Posts: 18

Rep: Reputation: 0
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().
 
Old 03-22-2007, 06:06 PM   #3
emge1
LQ Newbie
 
Registered: Sep 2006
Posts: 15

Original Poster
Rep: Reputation: 0
the pause man page says
Quote:
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.
how do you specify the signal-catching function?

thanks
 
Old 03-22-2007, 06:39 PM   #4
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,399
Blog Entries: 2

Rep: Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908
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/.

--- rod.
 
Old 03-23-2007, 04:01 AM   #5
nacio
LQ Newbie
 
Registered: Mar 2007
Location: Italy
Distribution: Debian
Posts: 18

Rep: Reputation: 0
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 :)
}

Last edited by nacio; 03-23-2007 at 04:03 AM.
 
Old 03-23-2007, 11:21 AM   #6
emge1
LQ Newbie
 
Registered: Sep 2006
Posts: 15

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by nacio
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?
 
Old 03-23-2007, 02:54 PM   #7
admiyo
LQ Newbie
 
Registered: Dec 2006
Location: SF Bay Area
Distribution: RHEL[3|4], Debian, CentOS
Posts: 15

Rep: Reputation: 0
I misread what you had done, and wrote this below. WHile it was a mistake, it is still worth knowing:

man 2 wait.


pid_t pid = fork()

if (pid == -1) {
/*handle error*/
exit 1;
}

if (pid){
pid_t retval;
int status;

/*i am the parent*/
retval = waitpid(pid, &status,0);

}else{

/*do child work*/

}


OK, so the signal thing posted above is more correct. Does the child process need any info from the parent, or does it just have to sleep?

Last edited by admiyo; 03-23-2007 at 02:57 PM.
 
Old 03-24-2007, 09:24 AM   #8
nacio
LQ Newbie
 
Registered: Mar 2007
Location: Italy
Distribution: Debian
Posts: 18

Rep: Reputation: 0
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.
 
Old 03-26-2007, 10:28 AM   #9
emge1
LQ Newbie
 
Registered: Sep 2006
Posts: 15

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by nacio
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?

Thanks a lot for all the ideas.
 
Old 03-26-2007, 02:53 PM   #10
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,399
Blog Entries: 2

Rep: Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908
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.
 
Old 03-26-2007, 08:48 PM   #11
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,665
Blog Entries: 4

Rep: Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945
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.
 
Old 03-27-2007, 01:10 PM   #12
admiyo
LQ Newbie
 
Registered: Dec 2006
Location: SF Bay Area
Distribution: RHEL[3|4], Debian, CentOS
Posts: 15

Rep: Reputation: 0
Another thing to try is the pipe trick. Do a man 3 pipe and it has smaple code showing how to set it up. Probably makes the most sense.

1. create pipe
2. fork
3. Child reads from pipe and blocks until it has something.
4. Parent does work and writes to pipe.

OK: looks like it is system specific which man page you get for this. This was on my Debian box:

#include <sys/wait.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

int
main(int argc, char *argv[])
{
int pfd[2];
pid_t cpid;
char buf;

assert(argc == 2);

if (pipe(pfd) == -1) { perror("pipe"); exit(EXIT_FAILURE); }

cpid = fork();
if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); }

if (cpid == 0) { /* Child reads from pipe */
close(pfd[1]); /* Close unused write end */

while (read(pfd[0], &buf, 1) > 0)
write(STDOUT_FILENO, &buf, 1);

write(STDOUT_FILENO, "\n", 1);
close(pfd[0]);
_exit(EXIT_SUCCESS);

} else { /* Parent writes argv[1] to pipe */
close(pfd[0]); /* Close unused read end */
write(pfd[1], argv[1], strlen(argv[1]));
close(pfd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
 
Old 03-27-2007, 01:51 PM   #13
emge1
LQ Newbie
 
Registered: Sep 2006
Posts: 15

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by sundialsvcs
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");
   }

}

Last edited by emge1; 03-27-2007 at 01:54 PM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Limitations of System Processes and Oracle Processes in RHEL AS3.0 sathyguy Linux - Enterprise 0 03-02-2007 11:52 PM
about IPC iclinux Programming 1 01-14-2005 11:16 PM
email synchronization (not file synchronization) Moebius Linux - Software 6 10-05-2004 05:31 AM
monitoring active processes and identifying the required processes. gajaykrishnan Programming 2 08-13-2004 01:58 AM
Standard Way To Share Memory Among Processes? Sys-V IPC? overbored Programming 1 06-21-2003 01:33 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 09:08 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration