实践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. [原创]基于VueJs的前后端分离框架搭建之完全攻略

    首先请原谅本文标题取的有点大,但并非为了哗众取宠.本文取这个标题主要有3个原因,这也是写作本文的初衷: (1)目前国内几乎搜索不到全面讲解如何搭建前后端分离框架的文章,讲前后端分离框架思想的就更少了, ...

  2. 转:Kafka 客户端TimeoutException问题之坑

    原文出自:http://www.jianshu.com/p/2db7abddb9e6 各种TimeoutException问题 会抛出org.apache.kafka.common.errors.Ti ...

  3. exp和imp的使用场合

    1.检测冲突 使用exp工具,在数据库中预先检测到物理或逻辑冲突. 导出的同时,将全扫描数据库中的每张表,读出所有行.如果某处表中有个损坏的块,必然能找到它. 2.可以用来快速恢复数据库. 使用exp ...

  4. webpack 4 + mockjs

    一.创建项目目录 二.添加开发依赖( html-webpack-plugin.webpack.webpack-cli.webpack-dev-server.webpack-api-mocker) 如下 ...

  5. FJUT第四周寒假作业[JL]最后的晚餐(动态规划)

    题目来源:http://210.34.193.66:8080/vj/Contest.jsp?cid=163#P4 [JL]最后的晚餐 TimeLimit:1000MS  MemoryLimit:100 ...

  6. ResizeObserver - 元素resize监听API

    Motivation 响应式网站/Web应用程序 根据视口大小调整内容展示方式.这通常通过CSS和media查询来完成.当CSS表现不好我们会使用Javascript. 比如document.addE ...

  7. Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 3 部分: Systemtap

    Systemtap的原理,Systemtap与DTrace比较,以及安装要求和安装步骤本系列文章详细地介绍了一个Linux下的全新的调式.诊断和性能测量工具Systemtap和它所依赖的基础kprob ...

  8. Dynamics CRM REST Builder

    今天介绍个很棒的工具叫CRM REST Builder,不管是2016之前的odata查询或者现在的web api都不在话下,界面如下,选项非常丰富 这里以retrieve multiple举个例子, ...

  9. Python 制作Android开发 所需的适配不同分辨率的套图

    使用Python做起工具来还真是爽,简单,方便,快捷.今天忙活了一下,制作出一个比较实用的小工具. 自动化套图制作,适配不同屏幕 尤其是对于android开发来说,要适配不同屏幕就需要多套切图,那么. ...

  10. [ExtJS5学习笔记]第三十五节 sencha extjs 5 组件查询方法总结

    一个UI前台组件肯定会比较多,我们通常习惯性的使用ID来获取需要操作的组件,但是这种方法是extjs推荐的么?有没有extjs推荐使用的获取组件的方法呢? 目录 目录 extjs的查询组件的API 查 ...