linux进程间通信之信号量集

AT&T的贝尔实验室,对Unix早期的进程间通信进行了改进和扩充,形成了"system V IPC",其通信进程主要局限在单个计算机内。IPC对象指的是共享内存(share memory)、消息队列(message queue)和信号灯集(semaphore)。

信号灯(semaphore),也叫信号量。它是不同进程间或一个给定进程内部不同线程间同步的机制。System V的信号灯是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。System V 信号灯由内核维护。主要函数semget,semop,semctl。

本文重点介绍的是semop函数。该函数主要功能是对信号灯进行P/V操作。

P操作责把当前进程由运行状态转换为阻塞状态,直到另外一个进程唤醒它。操作为:申请一个空闲资源(把信号量减1),若成功,则退出;若失败,则该进程被阻塞;

V操作负责把一个被阻塞的进程唤醒,它有一个参数表,存放着等待被唤醒的进程信息。操作为:释放一个被占用的资源(把信号量加1),如果发现有被阻塞的进程,则选择一个唤醒之。

semop函数原型如下:

int semop(int semid, struct sembuf  *sops, unsigned nsops);

semop操作中:sembuf结构的sem_flg成员可以为0、IPC_NOWAIT、SEM_UNDO 。为SEM_UNDO时,它将使操作系统跟踪当前进程对这个信号量的修改情况,如果这个进程在没有释放该信号量的情况下终止,操作系统将自动释放该进程持有的。

sembuf结构的sem_flg成员为SEM_UNDO时,它将使操作系统跟踪当前进程对这个信号量的修改情况,如果这个进程在没有释放该信号量的情况下终止,操作系统将自动释放该进程持有的信号量

问题描述:假设父子进程对一个文件进行写操作,但是这个文件同一时间只能有一个进程进行写操作。

示例程序如下:

#include <stdio.h>
        //……此处省略了头文件
        void P(int sid)
        {
            struct sembuf sem_p;
            sem_p.sem_num = 0;
            sem_p.sem_op = -1;
            sem_p.sem_flg = 0;

            if (semop(sid, &sem_p, 1) == -1)
            {
                perror("p op failed");
                exit(1);
            }
        }

        void V(int sid)
        {
            struct sembuf sem_p;
            sem_p.sem_num = 0;
            sem_p.sem_op = 1;
            sem_p.sem_flg = SEM_UNDO;
 //           sem_p.sem_flg = 0;

            if (semop(sid, &sem_p, 1) == -1)
            {
                perror("v op failed");
                exit(1);
            }
        }

        int main(int argc, char * argv[ ])
        {
            pid_t pid;
            int fd;
            key_t key;
            int sid;

            if ((fd = open("semset", O_RDWR | O_CREAT, 0666)) == -1)
            {
                perror("open");
                exit( -1);
            }

            if ((key=ftok("semset", 'a')) == -1)
            {
                perror("ftok");
                return -1;
            }

            if ((sid = semget(key, 1, IPC_CREAT | 0666)) == -1)
            {
                perror("createSemset");
                exit(-1);
            }

            if( -1==semctl(sid, 0, SETVAL, 1) )
            {
                perror("SETVAL");
                exit(1);
            }

            if ((pid=fork()) == -1)
            {
                perror("fork");
                exit(-1);
            }
            else if ( 0 == pid )
            {
                while(1)
                {
                    P(sid); 
                    printf("child writing\n");
                    sleep(1);
                    printf("child finish post\n");

                    V(sid);
                }
            }
            else
            {
                while(1)
                {
                    P(sid);
                    printf("parent writing");

                    sleep(1);
                    printf("parent writing finish post\n");

                    V(sid);
                }
            }

            return 0;
        }

在该程序中,父子进程都有可能执行P操作成功,因此,两个进程中的提示语句,交替显示。若通过kill命令把其中一个进程杀死,且该进程还没有执行V操作释放资源。若使用SEM_UNDO标志,则操作系统将自动释放该进程持有的信号量,从而使得另外一个进程可以继续工作。若没有这个标志,另外进程将P操作永远阻塞.因此,一般建议使用SEM_UNDO标志。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值