实践1:信号量实现进程互斥

父子进程执行流程如下:

父进程

子进程

P

P

O(print)

X(print)

sleep

sleep

O(print)

X(print)

V

V

sleep

sleep

从图中可以看出, O或X总是成对出现的, 要么两个O, 要么两个X;

/**P,V原语实现父子进程互斥使用终端**/
// 程序代码
int main(int argc,char *argv[])
{
    int semid = sem_create(IPC_PRIVATE);
    sem_setval(semid, 1);
    int count = 10;

    pid_t pid = fork();
    if (pid == -1)
        err_exit("fork error");
    else if (pid > 0)   //子进程
    {
        srand(getpid());
        while (count --)
        {
            sem_P(semid);
            //临界区开始
            cout << 'X';
            fflush(stdout); //一定要加上ffflush, 因为中断是行缓冲的
            sleep(rand()%3);
            cout << 'X';
            fflush(stdout);
            //临界区结束
            sem_V(semid);
            sleep(rand()%3);
        }
    }
    else                //父进程
    {
        srand(getpid());
        while (count --)
        {
            sem_P(semid);
            //临界区开始
            cout << 'O';
            fflush(stdout);
            sleep(rand()%3);
            cout << 'O';
            fflush(stdout);
            //临界区结束
            sem_V(semid);
            sleep(rand()%3);
        }
        wait(NULL);
        sem_delete(semid);
    }

    return 0;
}

实践2: 信号量集解决哲学家进餐问题

假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃饭,所以假设哲学家必须用两只餐叉吃东西, 而且他们只能使用自己左右手边的那两只餐叉。

/**
解决的方法采用的是: 只有左右两个刀叉都能够使用时,才拿起两个刀叉
实现了有死锁和无死锁的两种形式的wait_2fork(见下)
**/

int semid;
//没有死锁的wait
void wait_2fork(unsigned short no)
{
    unsigned short left = no;
    unsigned short right = (no+1)%5;
    struct sembuf sops[2] = {{left, -1, 0}, {right, -1, 0}};
    //同时获取左右两把刀叉
    if (semop(semid, sops, 2) == -1)
        err_exit("wait_2fork error");
}
/*
//有死锁的wait
void wait_2fork(unsigned short no)
{
    unsigned short left = no;
    unsigned short right = (no+1)%5;
    struct sembuf sops = {left, -1, 0};
    //获取左边的刀叉
    if (semop(semid, &sops, 1) == -1)
        err_exit("wait_2fork error");
    sleep(4);   //沉睡几秒, 加速死锁的产生
    sops.sem_num = right;
    //获取右边的刀叉
    if (semop(semid, &sops, 1) == -1)
        err_exit("wait_2fork error");
}
*/
//释放两把刀叉
void signal_2fork(unsigned short no)
{
    unsigned short left = no;
    unsigned short right = (no+1)%5;
    struct sembuf sops[2] = {{left, 1, 0}, {right, 1, 0}};
    if (semop(semid, sops, 2) == -1)
        err_exit("signal_2fork error");
}
//哲学家
void philosopher(unsigned short no)
{
    srand(time(NULL));
    while (true)
    {
        cout << no << " is thinking" << endl;
        sleep(rand()%5+1);
        cout << no << " is hunger" << endl;
        wait_2fork(no); //获取两把刀叉
        //进餐
        cout << "++ " << no << " is eating" << endl;
        sleep(rand()%5+1);
        signal_2fork(no);//释放两把刀叉
    }
}
int main()
{
    // 创建一个信号量集: 里面包含5个信号量
    semid = semget(IPC_PRIVATE, 5, IPC_CREAT|0666);
    if (semid == -1)
        err_exit("semget error");

    //将每个信号量都设初值为1
    union semun su;
    su.val = 1;
    for (int i = 0; i < 5; ++i)
        if (semctl(semid, i, SETVAL, su) == -1)
            err_exit("semctl SETVAL error");

    //创建四个子进程, 将每个进程的编号设定为no
    pid_t pid;
    unsigned short no = 0;
    for (unsigned short i = 0; i < 4; ++i)
    {
        pid = fork();
        if (pid == -1)
            err_exit("fork error");
        else if (pid == 0)
        {
            no = i+1;
            break;
        }
    }

    // 最后五个进程(4个子进程+1个父进程)都会汇集到此处,
    // 每个进程代表着一个哲学家,编号no: 0~4
    philosopher(no);

    return 0;
}

Linux IPC实践(12) --System V信号量(2)的更多相关文章

  1. Linux IPC实践(11) --System V信号量(1)

    信号量API #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget ...

  2. Linux IPC实践(9) --System V共享内存

    共享内存API #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int ...

  3. Linux IPC实践(6) --System V消息队列(3)

    消息队列综合案例 消息队列实现回射客户/服务器   server进程接收时, 指定msgtyp为0, 从队首不断接收消息 server进程发送时, 将mtype指定为接收到的client进程的pid ...

  4. Linux IPC实践(13) --System V IPC综合实践

    实践:实现一个先进先出的共享内存shmfifo 使用消息队列即可实现消息的先进先出(FIFO), 但是使用共享内存实现消息的先进先出则更加快速; 我们首先完成C语言版本的shmfifo(基于过程调用) ...

  5. Linux IPC实践(4) --System V消息队列(1)

    消息队列概述 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法(仅局限于本机); 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值. 消息队列也有管道一样的不足:  ...

  6. Linux IPC实践(5) --System V消息队列(2)

    消息发送/接收API msgsnd函数 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数 msgid: 由ms ...

  7. linux网络编程之system v信号量(一)

    今天起,学习信号量相关的知识,下面开始: 关于信号量,在前面已经介绍过了,这里回顾一下: 通过上面的描述,很容易就能想到信号量的一上数据结构: 下面再来回顾一下P.V原语: 所谓的原语就是指这段代码是 ...

  8. linux网络编程之system v信号量(二)

    今天迎来元旦假期的最后一天了,过得好快~昨天跟小伙伴们在军都滑雪陪儿爽,虽说上了两回中级道都摔得异常的惨烈,但是在初级道上学习"s"转弯还是有一些小心得,可以在要往高手迈进的前提, ...

  9. Linux中的System V信号量

    在进程同步,并发运行时,保证按序地访问共享资源是十分重要的.因此引入了临界区的概念,一次只能有一个线程进入临界区完成他的指令.而信号量(semaphore)的作用,类似于一个交通信号灯,它负责进程协作 ...

随机推荐

  1. dnc开源梦之队2018 开源项目精选集

    dnc开源梦之队2018 dnc开源项目选择标准 dnc = .NET Core.dotnet core 1.支持dnc 2.x,Github star数量100以上,最近2月活跃更新 2.轻量级.示 ...

  2. delphi 微信(WeChat)多开源代码

    在网上看到一个C++代码示例: 原文地址:http://bbs.pediy.com/thread-217610.htm 觉得这是一个很好的调用 windows api 的示例,故将其转换成了 delp ...

  3. css 中calc无效属性值问题

    width:calc(50%-20px); 这样书写是无效的因为calc中计算的两个因子同运算符号之间必须存在空格:

  4. 在ubuntu上安装最新稳定版本的node及npm

    背景 通过ubuntu官方apt安装工具安装的node是最新LTS版本的,而本人是个有点强迫症的人,喜欢追求新的东西,也就是想方设法想要去安装最新版本的node,所以本文也就产生了,附上ubuntu安 ...

  5. Node.js Buffer(缓冲区)

    JavaScript 语言自身只有字符串数据类型,没有二进制数据类型. 但在处理像TCP流或文件流时,必须使用到二进制数据.因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门 ...

  6. PHP 文件

    PHP 文件处理 fopen() 函数用于在 PHP 中打开文件. 打开文件 fopen() 函数用于在 PHP 中打开文件. 此函数的第一个参数含有要打开的文件的名称,第二个参数规定了使用哪种模式来 ...

  7. PHP FTP 函数

    PHP FTP 简介 FTP 函数通过文件传输协议 (FTP) 提供对文件服务器的客户端访问. FTP 函数用于打开.登录以及关闭连接,同时用于上传.下载.重命名.删除及获取文件服务器上的文件信息.不 ...

  8. pandas小记:pandas高级功能

    http://blog.csdn.net/pipisorry/article/details/53486777 pandas高级功能:面板数据.字符串方法.分类.可视化. 面板数据 {pandas数据 ...

  9. Unity插件 - MeshEditor(八)模型镜像特效

    将静态模型(带MeshFilter)按指定轴向.指定距离克隆一个镜像物体出来,思路很简单,将模型的顶点坐标按指定轴取反,并累加上设定的距离值,然后就完毕了!不过,因为镜像体的顶点镜像于之前模型的顶点, ...

  10. SpriteKit中的共享动作(Sharing Actions)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在SpriteKit中某些动作需要一些额外的延时,如果每次都重 ...