Linux IPC实践(12) --System V信号量(2)
实践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)的更多相关文章
- Linux IPC实践(11) --System V信号量(1)
信号量API #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> int semget ...
- Linux IPC实践(9) --System V共享内存
共享内存API #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int ...
- Linux IPC实践(6) --System V消息队列(3)
消息队列综合案例 消息队列实现回射客户/服务器 server进程接收时, 指定msgtyp为0, 从队首不断接收消息 server进程发送时, 将mtype指定为接收到的client进程的pid ...
- Linux IPC实践(13) --System V IPC综合实践
实践:实现一个先进先出的共享内存shmfifo 使用消息队列即可实现消息的先进先出(FIFO), 但是使用共享内存实现消息的先进先出则更加快速; 我们首先完成C语言版本的shmfifo(基于过程调用) ...
- Linux IPC实践(4) --System V消息队列(1)
消息队列概述 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法(仅局限于本机); 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值. 消息队列也有管道一样的不足: ...
- Linux IPC实践(5) --System V消息队列(2)
消息发送/接收API msgsnd函数 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 参数 msgid: 由ms ...
- linux网络编程之system v信号量(一)
今天起,学习信号量相关的知识,下面开始: 关于信号量,在前面已经介绍过了,这里回顾一下: 通过上面的描述,很容易就能想到信号量的一上数据结构: 下面再来回顾一下P.V原语: 所谓的原语就是指这段代码是 ...
- linux网络编程之system v信号量(二)
今天迎来元旦假期的最后一天了,过得好快~昨天跟小伙伴们在军都滑雪陪儿爽,虽说上了两回中级道都摔得异常的惨烈,但是在初级道上学习"s"转弯还是有一些小心得,可以在要往高手迈进的前提, ...
- Linux中的System V信号量
在进程同步,并发运行时,保证按序地访问共享资源是十分重要的.因此引入了临界区的概念,一次只能有一个线程进入临界区完成他的指令.而信号量(semaphore)的作用,类似于一个交通信号灯,它负责进程协作 ...
随机推荐
- 89. Gray Code(中等,了解啥是 gray code)
知道啥是 gray code 就是收获了. 下面介绍了 gray code 发明的 motivation, 了解动机后就知道啥是 gray code 了. https://zh.wikipedia.o ...
- 72. Edit Distance(困难,确实挺难的,但很经典,双序列DP问题)
Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2 ...
- Zookeeper和Chubby【分布式协调系统】
前言(对于协调系统来说其客户端往往是分布式集群) 大规模分布式系统需要解决各种类型的协调需求: 当集群中有新的进程或服务器加入时,如何探测到它的加入?如何能够自动获取配置参数? 当配置信息被某个进程或 ...
- Jupyter Notebook 快速入门
Jupyter Notebook(此前被称为 IPython notebook)是一个交互式笔记本,支持运行 40 多种编程语言.在本文中,我们将介绍 Jupyter notebook 的主要特性,以 ...
- python学习之路网络编程篇(第一篇)socket初识
什么是socket 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为socket.socket通常也称为“套接字”,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的 ...
- 如何搭建ssh服务?
为了日后便于查询,本文所涉及到的所有命令集合如下: rpm -qa | grep openssh #查看是否安装了openssh软件 service sshd status #服务端的ssh状态 if ...
- python笔记十四(高阶函数——map/reduce、filter、sorted)
一.map/reduce 1.map() map(f,iterable),将一个iterable对象一次作用于函数f,并返回一个迭代器. >>> def f(x): #定义一个函数 ...
- 使用Docker搭建GitLab
使用docker-compose快速启动GitLab.(当然前提是你先安装docker-compose,安装方式见博客:http://blog.csdn.net/yulei_qq/article/de ...
- Programming In Scala笔记-第八章、函数与闭包
当程序的代码量增大时,就需要对各功能模块进行分割,这些分割的小模块就是本文中接下来会进行分析的函数.接下来的部分会讲解包括函数嵌套,函数字面量,以及函数值等概念. 一.方法 一会函数一会方法的,是不是 ...
- TensoFlow实现条件语句
import tensorflow as tf a = tf.constant(20) b = tf.constant(10) result1 = tf.cond(a > b, lambda: ...