Posix匿名信号量与fork

来源:互联网 发布:资海网络集团电话 编辑:程序博客网 时间:2024/06/06 02:59

Linux Manual Page的表述

这是sem_init的man page,注意我下划的一句话。

NAME

sem_init - initialize an unnamed semaphore

SYNOPSIS

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

Link with -pthread.

DESCRIPTION

sem_init() initializes the unnamed semaphore at the address pointed to by sem. The value argument specifies the initial value for the semaphore.

The pshared argument indicates whether this semaphore is to be shared between the threads of a process, or between processes.

If pshared has the value 0, then the semaphore is shared between the threads of a process, and should be located at some address that is visible to all threads(e.g., a global variable, or a variable allocated dynamically on the heap).

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.) Any process that can access the shared memory region can operate on the semaphore using sem_post(3), sem_wait(3), etc.

Initializing a semaphore that has already been initialized results in undefined behavior.

初看,貌似fork()之后,子进程可以与父进程共享其Posix信号量。不过,按照常理思考,如果这个信号量存储在父进程的进程空间中,在fork()之后,子进程拥有的不过是其副本而已,他们的信号量操作应该不能同步才是。


编码测试

#include <stdio.h>#include <semaphore.h>#include <fcntl.h>#include <unistd.h>#include <sys/time.h>#include <signal.h>#include <stdlib.h>sem_t * test = NULL;void sigalarm(int signo){    if(sem_post(test) < 0)    {        printf("Child: sem_post fialed\n");        return;    }    printf("Child: Wake up Parent\n");}int main(void){    __pid_t pid;    struct itimerval it;    test = malloc(sizeof(sem_t));    if(test == NULL)    {        printf("malloc failed\n");        return 1;    }    if(sem_init(test, 1, 0) < 0)    {        printf("sem_init failed\n");        return 1;    }    pid = fork();    if(pid == 0)    {//Child        it.it_interval.tv_sec = 0;        it.it_interval.tv_usec = 100000;        it.it_value.tv_sec = 0;        it.it_value.tv_usec = 100000;        if(signal(SIGALRM, sigalarm) == SIG_ERR)        {            printf("Child: signal failed\n");            return 1;        }        if(setitimer(ITIMER_REAL, &it, NULL) < 0)        {            printf("Child: setitimer failed\n");            return 1;        }        while(1)        {            sleep(1);        }        if(sem_destroy(test) < 0)        {            printf("Child: sem_destroy failed\n");        }    }    else if(pid > 0)    {//Parent        while(1)        {            if(sem_wait(test) < 0)            {                printf("Parent: sem_wait failed\n");                continue;            }            printf("Parent: waked up by Child\n");        }        if(sem_destroy(test) < 0)        {            printf("Parent: sem_destroy failed\n");        }    }    else    {        printf("fork failed\n");        return 1;    }    return 0;}

运行之后

Child: Wake up ParentChild: Wake up ParentChild: Wake up ParentChild: Wake up ParentChild: Wake up ParentChild: Wake up ParentChild: Wake up ParentChild: Wake up ParentChild: Wake up Parent

这说明父进程一直阻塞在sem_wait()。


总结

Posix匿名信号量,如果需要跨进程共享,必须放在共享内存区域(mmap,shm_open,shmget)。父进程中的静态存储区(全局变量)、堆(malloc)或者栈(局部变量)中存储的Posix匿名信号量,在fork()之后,父子两个进程分别拥有各自副本,并不能据此利用他们同步操作。


扩展阅读

信号量 sem_t 进程同步

内存区划分、内存分配、常量存储区、堆、栈、自由存储区、全局区[C++][内存管理]

0 0