信号量&同步与互斥
2018-04-08 11:28
225 查看
在介绍信号量&同步与互斥之前,我们先来了解一下生产者与消费者模型。
生产者消费者的模型提出了三种关系,两种角色,一个场所
三种关系:
- 生产者之间的互斥关系
- 消费者之间的竞互斥关系
- 生产者和消费者之间互斥和同步关系(同一时刻只能有一个,要么在生产,要么在消费,这就是互斥关系,只能在生产者生产完了之后才能消费,这就是同步关系)
两个角色:一般是用进程或线程来承担生产者或消费者
一个场所:有效的内存区域。(如单链表,数组)
我们就可以把这个想象成生活中的超市供货商,超市,顾客的关系,超市供货商供货,超市是摆放货物的场所,然后用户就是消费的。
信号量主要用于同步和互斥,那么什么是同步与互斥呢?
进程互斥:
由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系称为互斥。
系统中的某些资源一次只允许一个进程使用,这样的资源称为临界资源或者互斥资源。
进程中涉及到互斥资源的程序段叫临界区。
进程同步
进程同步指的是多个进程需要相互配合共同完成一项任务。
信号量和P、V原语
信号量和p、v原语由大佬Dijkstra(迪杰斯特拉)提出
信号量
互斥:P、V在同一进程中
同步:P、V在不同进程中
信号量值的含义
s > 0: s表示可用资源的个数
s = 0: 表示无可用资源,无等待进程
s < 0: |s|表示等待队列中进程个数
信号量结构体的伪代码
P原语
V原语
简单的介绍之后,就让我们来用代码测试一下同步与互斥吧!
这里,我们按照二元信号量来测试。
comm.h
comm.c
test_sem.c
最后奉上Makefile
此时,显示器只有一个,两个进程同时打印,显示器称为临界资源,使用二元信号量(互斥锁)进行保护
执行效果如下:
所有AB都是成对出现,不会出现交叉的情况,那如果去掉PV呢?
出现打印的内容相互影响
在ctrl + c之后使用ipcs -s 查看信号量,及ipcsrm -s + semid删除信号量
关于ipcs&ipcrm的使用,参照我得博客:ipcs和ipcrm的使用
注意,删除信号量不是必须通过手动删除,这里只是为了演示相关指令,删除IPC资源是进程应该做的事。
由于个人能力有限,以上的说明可能有Bug或者有什么不妥之处,欢迎发邮件到我的邮箱( Cyrus_wen@163.com )批评指正!
生产者将数据放入缓冲区,消费者将数据从缓冲区取走消费。
生产者消费者的模型提出了三种关系,两种角色,一个场所
三种关系:
- 生产者之间的互斥关系
- 消费者之间的竞互斥关系
- 生产者和消费者之间互斥和同步关系(同一时刻只能有一个,要么在生产,要么在消费,这就是互斥关系,只能在生产者生产完了之后才能消费,这就是同步关系)
两个角色:一般是用进程或线程来承担生产者或消费者
一个场所:有效的内存区域。(如单链表,数组)
我们就可以把这个想象成生活中的超市供货商,超市,顾客的关系,超市供货商供货,超市是摆放货物的场所,然后用户就是消费的。
信号量主要用于同步和互斥,那么什么是同步与互斥呢?
进程互斥:
由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系称为互斥。
系统中的某些资源一次只允许一个进程使用,这样的资源称为临界资源或者互斥资源。
进程中涉及到互斥资源的程序段叫临界区。
进程同步
进程同步指的是多个进程需要相互配合共同完成一项任务。
司机 p1 售票员 p2 while(1) while(1) { { 启动车辆; 关门; 正常运行; 售票; 到站停车; 开门; } }
信号量和P、V原语
信号量和p、v原语由大佬Dijkstra(迪杰斯特拉)提出
信号量
互斥:P、V在同一进程中
同步:P、V在不同进程中
信号量值的含义
s > 0: s表示可用资源的个数
s = 0: 表示无可用资源,无等待进程
s < 0: |s|表示等待队列中进程个数
信号量结构体的伪代码
信号量本质上是一个计数器 struct semaphore { int value; pointer_PCB queue; }
P原语
p(s){ s.value = s.value--; if(s.value < 0){ 该进程状态设置为等待状态; 将该进程的PCB插入相应等待队列s.queue末尾; } }
V原语
V(s){ s.value = s.value++; if(s.value <= 0){ 唤醒相应等待队列s.queue中等待的一个进程 改变其状态为就绪态 将其插入就绪队列 } }
简单的介绍之后,就让我们来用代码测试一下同步与互斥吧!
这里,我们按照二元信号量来测试。
comm.h
#pragma once #include<stdio.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h> #include<unistd.h> #include<sys/wait.h> #define PATHNAME "." #define PROJ_ID 0x6666 union semun{ int val; struct semid_ds *buf; unsigned short *array; struct seminfo *_buf; }; int createSemSet(int nums); int initSem(int semid, int nums, int initVal); int getSemSet(int nums); int P(int semid,int who); int V(int semid,int who); int destroySemSet(int semid);
comm.c
#include"comm.h" static int commSemSet(int nums,int flags){ key_t _key = ftok(PATHNAME,PROJ_ID); if(_key < 0){ perror("ftok"); return -1; } int semid = semget(_key, nums, flags); if(semid < 0){ perror("semget"); return -2; } return semid; } int createSemSet(int nums){ return commSemSet(nums, IPC_CREAT|IPC_EXCL|0666); } int getSemSet(int nums){ return commSemSet(nums, IPC_CREAT); } int initSem(int semid, int nums, int initVal){ union semun _un; _un.val = initVal; if(semctl(semid, nums, SETVAL, _un) < 0){ perror("semctl"); return -1; } return 0; } static int commPV(int semid, int who, int op){ struct sembuf _sf; _sf.sem_num = who; _sf.sem_op = op; _sf.sem_flg = 0; if(semop(semid, &_sf, 1) < 0){ perror("semop"); return -1; } return 0; } int P(int semid, int who){ return commPV(semid, who, -1); } int V(int semid, int who){ return commPV(semid, who, 1); } int destroySemSet(int semid){ if(semctl(semid, 0, IPC_RMID) < 0){ perror("semctl"); return -1; } return 0; }
test_sem.c
#include"comm.h" int main(){ int semid = createSemSet(1); initSem(semid, 0, 1); pid_t id = fork(); if(id == 0){ int _semid = getSemSet(0); while(1){ P(_semid,0); printf("A"); fflush(stdout); usleep(123456); printf("A"); fflush(stdout); usleep(321456); V(_semid, 0); } } else{ while(1){ P(semid, 0); printf("B"); fflush(stdout); usleep(223456); printf("B"); fflush(stdout); usleep(12346); V(semid, 0); } wait(NULL); } destroySemSet(semid); return 0; }
最后奉上Makefile
test_sem:comm.c test_sem.c gcc -o $@ $^ .PHONY:clean clean: rm -f test_sem
此时,显示器只有一个,两个进程同时打印,显示器称为临界资源,使用二元信号量(互斥锁)进行保护
执行效果如下:
所有AB都是成对出现,不会出现交叉的情况,那如果去掉PV呢?
出现打印的内容相互影响
在ctrl + c之后使用ipcs -s 查看信号量,及ipcsrm -s + semid删除信号量
关于ipcs&ipcrm的使用,参照我得博客:ipcs和ipcrm的使用
注意,删除信号量不是必须通过手动删除,这里只是为了演示相关指令,删除IPC资源是进程应该做的事。
由于个人能力有限,以上的说明可能有Bug或者有什么不妥之处,欢迎发邮件到我的邮箱( Cyrus_wen@163.com )批评指正!
相关文章推荐
- 同步和互斥的POSIX支持(读写锁、信号量和记录锁)
- 信号量解决进程的同步和互斥
- linux 多线程编程 之 信号量互斥同步
- semget函数 semopt 采用信号量处理多进程互斥同步
- 多线程--同步互斥&生产者消费者(一)
- Linux利用信号量实现线程的同步与互斥
- 用信号量解决进程的同步与互斥探讨
- 操作系统学习笔记(9) 互斥和同步的信号量算法
- linux中的生产者和消费者问题--信号量 互斥 同步
- 同步和互斥的POSIX支持(读写锁、信号量和记录锁)
- 信号量的互斥与同步
- 同步、异步、互斥、信号量、阻塞、非阻塞
- 信号量学习 & 共享内存同步
- 一起talk C栗子吧(第一百回:C语言实例--使用信号量进行进程间同步与互斥一)
- AND型信号量与信号量集-----进程的同步与互斥面向对象的解决方案(二)
- 进程与线程;同步与互斥:事件,信号量,临界区,互斥量
- 线程间的同步与互斥—信号量
- 多线程的同步与互斥机制(生产者&消费者模型)
- 同步和互斥的POSIX支持(读写锁、信号量和记录锁)
- 生产者-消费者问题实现 (linux下C同步信号量和互斥信号量的应用)