进程间通信之信号量semaphore--linux内核剖析( 四 )


  • 返回0
  • 返回阻塞在该信号量上的进程或线程数目
linux采用返回的第一种策略 。
sem_wait(或sem_trywait)相当于P操作 , 即申请资源 。
int sem_wait(sem_t *sem); // 这是一个阻塞的函数测试所指定信号量的值,它的操作是原子的 。
  • 若sem>0 , 那么它减1并立即返回 。
  • 若sem==0 , 则睡眠直到sem>0 , 此时立即减1 , 然后返回 。
int sem_trywait(sem_t *sem); // 非阻塞的函数其他的行为和sem_wait一样 , 除了: 若sem==0 , 不是睡眠 , 而是返回一个错误EAGAIN 。
sem_post相当于V操作 , 释放资源 。
int sem_post(sem_t *sem);把指定的信号量sem的值加1;
呼醒正在等待该信号量的任意线程 。注意:在这些函数中 , 只有sem_post是信号安全的函数 , 它是可重入函数
无名信号量在多线程间的同步无名信号量的常见用法是将要保护的变量放在sem_wait和sem_post中间所形成的 临界区内 , 这样该变量就会被保护起来 , 例如:
#include #include #include #include #include int number; // 被保护的全局变量sem_t sem_id;void* thread_one_fun(void *arg){sem_wait(printf("thread_one have the semaphore\n");number++;printf("thread_one : number = %d\n", number);sem_post(return NULL;}void* thread_two_fun(void *arg){sem_wait(printf("thread_two have the semaphore \n");number--;printf("thread_two : number = %d\n", number);sem_post(return NULL;}int main(int argc, char *argv[]){number = 1;pthread_t id1, id2;sem_init(pthread_create(pthread_create(pthread_join(id1, NULL);pthread_join(id2, NULL);printf("main...\n");return 0;}上面的例程 , 到底哪个线程先申请到信号量资源 , 这是随机的 。
进程1先执行 , 进城2后执行
进程间通信之信号量semaphore--linux内核剖析文章插图
进程2先执行 , 进城1后执行
进程间通信之信号量semaphore--linux内核剖析文章插图
如果想要某个特定的顺序的话 , 可以用2个信号量来实现 。 例如下面的例程是线程1先执行完 , 然后线程2才继续执行 , 直至结束 。
#include #include #include #include #include #include #include int number;// 被保护的全局变量sem_t sem_id1, sem_id2;/* *线程1, *对sem_id1加锁(P操作)以后 *将number增加1 *同时对sem_id2进行释放 , V操作 * **/void* thread_one_fun(void *arg){sem_wait(printf("thread_one have the semaphore\n");number++;printf("number = %d\n",number);sem_post(return NULL;}/* *线程2, *对sem_id2加锁(P操作)以后 *将number减少1 *同时对sem_id1进行释放 , V操作 * **/void* thread_two_fun(void *arg){sem_wait(printf("thread_two have the semaphore \n");number--;printf("number = %d\n",number);sem_post(return NULL;}int main(int argc,char *argv[]){number = 1;pthread_t id1, id2;/**由于程序初始时, sem_id1可进入, sem_id2不可进入*两个线程的动作如下:*thread one P(id1)number++ V(id2)*thread two P(id2)number-- V(id1)*而id1可进入, id2不可进入*因此thread one先执行*如果将id1与id2的顺序交换, 则执行顺序相反* */sem_init(// 空闲的sem_init(// 忙的pthread_create(pthread_create(pthread_join(id1, NULL);pthread_join(id2, NULL);printf("main...\n");return EXIT_SUCCESS;}无名信号量在相关进程间的同步说是相关进程 , 是因为本程序中共有2个进程 , 其中一个是另外一个的子进程(由fork产生)的 。
本来对于fork来说 , 子进程只继承了父进程的代码副本 , mutex理应在父子进程中是相互独立的两个变量 , 但由于在初始化mutex的时候 , 由pshared = 1指定了mutex处于共享内存区域 , 所以此时mutex变成了父子进程共享的一个变量 。 此时 , mutex就可以用来同步相关进程了 。
#include #include #include #include #include #include #include #include #include int main(int argc, char **argv){intfd, i;intnloop = 10, zero = 0;int*ptr;sem_tmutex;//open a file and map it into memoryfd = open("log.txt", O_RDWR | O_CREAT, S_IRWXU);write(fd,ptr = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);close(fd);/* create, initialize semaphore */if(sem_init(exit(0);}if (fork() == 0){/* child process*/for (i = 0; i < nloop; i++){sem_wait(printf("child: %d\n", (*ptr)++);//sleep(1);sem_post(}exit(0);}/* back to parent process */for (i = 0; i < nloop; i++){sem_wait(printf("parent: %d\n", (*ptr)++);//sleep(1);sem_post(}exit(0);}
进程间通信之信号量semaphore--linux内核剖析文章插图
有名信号量有名信号量的特点是把信号量的值保存在文件中 。
这决定了它的用途非常广:既可以用于线程 , 也可以用于相关进程间 , 甚至是不相关进程 。
有名信号量能在进程间共享的原因由于有名信号量的值是保存在文件中的 , 所以对于相关进程来说 , 子进程是继承了父进程的文件描述符 , 那么子进程所继承的文件描述符所指向的文件是和父进程一样的 , 当然文件里面保存的有名信号量值就共享了 。