Thread: Need help with process synchronization

  1. #1
    Registered User
    Join Date
    Nov 2011
    Posts
    4

    Need help with process synchronization

    Hello Everyone,

    I am trying to write a program on process syncronization using semaphore. The aim is that the parent process will print first, then the child will print, then the parent again and so on but it is not working. Please see the code below:

    Code:
    #include <stdio.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <semaphore.h>
    sem_t sem1, sem2;
    
    int main(void)
    {
    int     i, j, fd;
    pid_t   pid;
    sem_init(&sem1, 1, 0);
    sem_init(&sem2, 1, 0);
    
    
    /* fork a new process */
    if (fork() == 0) {
            /* The child will run this section of code */
            for (j=0;j<5;j++)
                    {
                    /* have the child "wait" for the semaphore */
                    printf("Child PID(%d): waiting on sem1\n", getpid());
                    sem_wait(&sem1);
                    /* the child decremented the semaphore */
                    printf("Child PID(%d): decremented sem1.\n", getpid());
                    sem_post(&sem2);
                    printf("Chile PID(%d): posting sem2.\n", getpid());
                    }
            /* exit the child process */
            printf("Child PID(%d): exiting...\n", getpid());
            exit;
    } else {
        /* The parent will run this section of code */
        /* give the child a chance to start running */
        sleep(2);
        for (i=0;i<5;i++)
            {
                    /* increment (post) the semaphore */
                    printf("Parent PID(%d): posting sem1.\n", getpid());
                    sem_post(&sem1);
                    printf("Parent PID(%d): waiting on sem2\n", getpid());
                    sem_wait(&sem2);
                    printf("Parent PID(%d): decremented sem2.\n", 
                            getpid());
            }
            /* exit the parent process */
            printf("Parent PID(%d): exiting...\n", getpid());
            return 0;
    }
    The output is given below:
    Child PID(30214): waiting on sem1
    Parent PID(30213): posting sem1.
    Parent PID(30213): waiting on sem2

    Looks like the child procress waiting on sem1 is not awaken. Could anyone please point out the mistake?

    Thanks,
    With Reagards,
    Indranil

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    There is a very misleading/ambiguous statement in my linux man sem_init:

    Quote Originally Posted by man sem_init
    If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2)). (Since a child created by fork(2) inherits its parent’s memory mappings, it can also access the semaphore.)
    The bold bit is not in the POSIX standard man page:
    sem_init
    It is not false, but it is elliptical (missing further explication). A fork is a copy of the parents memory, addresses remain the same because they are virtual, however, the memory is not automatically shared. But if a copy of an address refers to a shared memory object, then it is the same object in both forks (and this is what the poorly worded bit in parentheses is meant to indicate).

    Ie, the idea is that you use shared memory for the semaphore, and both forks receive a copy of an address that can be used to refer to it:

    Code:
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <semaphore.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    
    typedef struct {
    	sem_t one;
    	sem_t two;
    } SemPair;
    
    int main(int argc, const char *argv[]) {
    	int shm = shm_open("/test", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
    	ftruncate(shm, sizeof(sem_t));
    	SemPair *sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0);
    
    	sem_init(&(sem->one), 1, 0);
    	sem_init(&(sem->two), 1, 0);
    
    	pid_t pid = fork();
    	if (!pid) {
    		while (1) {
    			sem_wait(&(sem->two));
    			fprintf(stderr,"Child %d\n", getpid());
    			sem_post(&(sem->one));
    		}
    	} else {
    		while (1) {
    			sem_post(&(sem->two));
    			sem_wait(&(sem->one));
    			fprintf(stderr,"Parent %d\n", getpid());
    			sleep(1); /* regulate both processes */
    		}
    	}
    	return 0;
    }
    This does a perfect:

    root~/C»./a.out
    Child 4880
    Parent 4879
    Child 4880
    Parent 4879
    Child 4880
    Parent 4879
    Child 4880
    Parent 4879
    [...]


    However, if you change the first three lines of main() to:
    Code:
    	SemPair *sem = malloc(sizeof(*sem));
    The whole thing fails, because the semaphore is not shared between the processes.
    Last edited by MK27; 11-16-2011 at 09:50 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Code:
    while (pointNotYetMade())
        Use mmap()'d files for shared memory between processes, not shm!
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by brewbuck View Post
    Code:
    while (pointNotYetMade())
        Use mmap()'d files for shared memory between processes, not shm!
    How is writing a file to disk going to represent an improvement? Why bother to do that when it is not necessary? Not to mention what a hassle it creates.

    I've actually never used these semaphores (POSIX:SEM) before; I've just used POSIX:XSI between threads and not processes.

    Anyway, I notice that the shared mem issue can be resolved by using sem_open() to get an address rather than creating the type and using sem_init().

    Code:
    #include <semaphore.h>
    #include <sys/mman.h>
    #include <fcntl.h>
    
    typedef struct {
    	sem_t *one;
    	sem_t *two;
    } SemPair;
    
    int main(int argc, const char *argv[]) {
    	SemPair sem;
    	sem.one = sem_open("/test1", O_CREAT, S_IRUSR | S_IWUSR, 0);
    	sem.two = sem_open("/test2", O_CREAT, S_IRUSR | S_IWUSR, 0);
    
    	pid_t pid = fork();
    	if (!pid) {
    		while (1) {
    			sem_wait(sem.two);
    			fprintf(stderr,"Child %d\n", getpid());
    			sem_post(sem.one);
    		}
    	} else {
    		while (1) {
    			sem_post(sem.two);
    			sem_wait(sem.one);
    			fprintf(stderr,"Parent %d\n", getpid());
    			sleep(1); /* regulate both processes */
    		}
    	}
    	return 0;
    }
    Last edited by MK27; 11-17-2011 at 09:09 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by MK27 View Post
    How is writing a file to disk going to represent an improvement? Why bother to do that when it is not necessary? Not to mention what a hassle it creates.
    1. SysV shared memory segments are persistent unless deliberately deleted. If the apps are buggy, and exit or crash without destroying the segment, the whole thing leaks. Unless you are a programmer or a sysadmin, you will not think to look for this, or know how to fix it when it happens. With memory mapped files, the memory simply goes away. Yes, you now have a file sitting on disk wasting space, but this is better than wasting memory.

    2. A real file in the filesystem is easy to find. You can even open it up in a text editor and see what's going on in there. This is GREAT for debugging.

    3. shm uses a separate namespace. Memory mapped files use the same namespace as everything else (i.e., the filesystem).

    4. The memory mapped file serves as its own backing store, meaning your shared pages won't use swap space if they get evicted -- they'll just go back to disk again.

    5. There is no reason disk activity has to occur, at least until all the instances of the mapping are closed, or if somebody calls msync(). Memory mapped files aren't constantly be synchronized to disk, that would suck infinitely.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Simple process synchronization question
    By AnTriber in forum C Programming
    Replies: 3
    Last Post: 09-10-2010, 05:51 PM
  2. Synchronization ...
    By Deb in forum C Programming
    Replies: 5
    Last Post: 04-12-2007, 11:26 PM
  3. thread synchronization
    By l2u in forum Windows Programming
    Replies: 2
    Last Post: 08-23-2006, 01:12 PM
  4. Clock Synchronization
    By tyler4588 in forum Tech Board
    Replies: 1
    Last Post: 08-20-2003, 05:17 PM
  5. thread synchronization
    By codec in forum C++ Programming
    Replies: 7
    Last Post: 03-12-2003, 04:18 PM

Tags for this Thread