进程通信(信号量)

信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的

通信资源(文件,外部设备)来实现进程间通信,它本身只是一种外部资源的标识。信号

量在此过程中负责数据操作的互斥、同步等功能。

当请求一个使用信号量来表示的资源时,进程需要先读取信号量的值来判断资源是否可用。大于0,资源可以请求,等于0,无资源可用,进程会进入睡眠状态直至资源可用。

当进程不再使用一个信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减

操作均为原子操作,这是由于信号量主要的作用是维护资源的互斥或多进程的同步访问。

而在信号量的创建及初始化上,不能保证操作均为原子性。

一、为什么用信号量

为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,

它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。

临界区域是指执行数据更新的代码需要独占式地执行。而信号量就可以提供这样的一种访

问机制,让一个临界区同一时间只有一个线程在访问它, 也就是说信号量是用来调协进程

对共享资源的访问的。其中共享内存的使用就要用到信号量。

二 信号量的工作原理

由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:

P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行

V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂

起,就给它加1.

sem.h

  1 #pragma once
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<sys/ipc.h>
  6 #include<sys/sem.h>
  7 #include<sys/types.h>
  8 #define _PATH_  "."
  9 #define _PROJ_ID 0X6666
 10  union semun {
 11                int              val;    /* Value for SETVAL */
 12                struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
 13                unsigned short  *array;  /* Array for GETALL, SETALL */
 14                struct seminfo  *__buf;  /* Buffer for IPC_INFO
 15                                            (Linux-specific) */
 16            };
 17 int create_sem_set(int _sem_nums);
 18 int get_sem_set();
 19 int init_sem_set(int _sem_id,int _sem_num,int _init_val);
 20 int destroy_sem_set(int sem_id); 
 21 int p_sem_elem(int _sem_id,int _sem_num);
 22 int v_sem_elem(int _sem_id,int _sem_num);
 
 sem.c
   1 #include "sem.h"
  2 
  3 static int com_create_sem_set(int _sem_nums,int flags)
  4 {
  5   key_t key=ftok(_PATH_,_PROJ_ID);
  6   if(key<0)
  7   {
  8     perror("ftok\n");
  9     return -1;
 10   }
 11   int _sem_id=semget(key,_sem_nums,flags);
 12   if(_sem_id<0)
 13   {
 14     perror("semget");
 15     return -1;
 16   }
 17   return _sem_id;
 18 }
 19 int create_sem_set(int _sem_nums)
 20 {
 21   int flags=IPC_CREAT|IPC_EXCL|0666;
 22   return com_create_sem_set(_sem_nums,flags);
 23 
 24 }
 25 int get_sem_set(int _sem_nums)
 26 {
 27    int flags=IPC_CREAT;
 28    return com_create_sem_set(_sem_nums,flags);
 29 
 30 }
 31 int init_sem_set(int _sem_id,int _sem_num,int _init_val)
 32 {
 33  union semun _semnu ;
 34  _semnu.val=_init_val;
 35  if(semctl(_sem_id,_sem_num,SETVAL,_semnu))
 36  {
 37    perror("semctl");
 38    return -1;
 39  }
 40   return 0;
 41 }
 42 int destroy_sem_set(int _sem_id)
 43 {
 44   if(semctl(_sem_id,0,IPC_RMID))
 45   {
 46     perror("semctl");
 47     return -1;
 48   }
 49   return 0;
 50 
 51 }
 52 int com_op_sem_elem(int _sem_id,int op,int _sem_num)
 53 {
 54   struct sembuf _sembuf;
 55   _sembuf.sem_num=_sem_num;
 56   _sembuf.sem_op=op;
 57   _sembuf.sem_flg=0;
 58   if(semop(_sem_id,&_sembuf,1))
 59   {
 60    perror("semop");
 61    return -1;
 62   }
 63   return 0;
 64 
 65 }
 66 int p_sem_elem(int _sem_id,int _sem_num)
 67 {
 68   return com_op_sem_elem(_sem_id,-1,_sem_num);
 69 }
 70 int v_sem_elem(int _sem_id,int _sem_num)
 71 {
 72    return com_op_sem_elem(_sem_id,1,_sem_num);
 73 }   
  
  test.c:
  1 #include "sem.h"
  2 int main()
  3 {
  4 
  5 int _sem_id=create_sem_set(1);
  6 pid_t pid=fork();
  7 init_sem_set(_sem_id,0,1);
  8 if(pid<0)
  9 {
 10     perror("pid");
 11     return -1;
 12 }
 13 else if(pid==0)
 14 {
 15    while(1)
 16    {
 17    int _sem_id= get_sem_set(1);
 18    p_sem_elem(_sem_id,0);
 19    printf("A");
 20    sleep(3);
 21    printf("A");
 22    fflush(stdout);
 23    sleep(2);
 24    v_sem_elem(_sem_id,0);
 25    }
 26 }
 27 
 28 //destroy_sem_set(_sem_id);;
 29 else
 30 {
 31     while(1)
 32     {
 33     p_sem_elem(_sem_id,0);
 34     printf("B");
 35     sleep(5);
 36     printf("B");
 37     fflush(stdout);
 38     sleep(5);
 39     v_sem_elem(_sem_id,0);
 40 
 41     }
 42 waitpid(pid,NULL,0);
 43 destroy_sem_set(_sem_id);
 44 }
 45 return 0;
 46 }
 
 
 Makefile:
  1 SEM:sem.c test.c
  2     gcc -o [email protected] $^
  3 .PHONY:clean
  4 clean:
  5     rm -f SEM
  
  
  结果:
 [[email protected] SEM]$ ./SEM
AABBAAAABBAAAABBAAAABBAAAABBAAAABBAAAABBAAAABBAAAABBAA^C
时间: 2024-08-11 00:29:41

进程通信(信号量)的相关文章

进程通信(二)&mdash;&mdash; 信号量&amp;内存共享

内存共享是进程间常用的通信方式,可以实现两个完全独立的进程通信. 在访问共享内存时,同时需要信号量进行访问控制. 使用ipcs -m命令可以查看系统共享内存,ipce -m + key 可以删除指定的共享内存. 对共享内存操作时,使用信号量对共享内存进行保护,类似与线程中的互斥锁.都可以看做是通过PV操作实现临界资源保护. P:对信号量标记位-1,获取信号量,如果标记位为0,表示有其他进程占用资源,无法获取. V:对信号量标记位+1,释放信号量,将资源释放,给其他进程使用. 信号量和内存共享需要

Linux 进程通信之 ——信号和信号量总结

如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存.       所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一样.通信是一个广义上的意义,不仅仅指传递一些massege.他们的用法是基本相同的,所以仅仅要掌握了一种的用法,然后记住其他的用法就能够了. 1. 信号       在我学习的内容中,主要接触了信号来实现同步的机制,据说信号也能够用来做其他的事      情,可是我还不知道做什么.       信号和信号量是

linux进程通信之SYSTEM V信号量

信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有.信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明它被占用,测试的线程要进入睡眠队列中,等待被唤醒. 一.信号量的分类: 在学习信号量之前,我们必须先知道--Linux提供两种信号量: (1) 内核信号量,由内核控制路径使用. (2) 用户态进程使用的信号量,这种信号量又分为POSIX信号量和SYSTEM V信号量. POSIX信号量又分为有名信号量和无名信号量.有名信号量,其值保存在文件

第七课 进程通信

unix_c_07.txt================第七课 进程通信================一.基本概念------------1. 何为进程间通信~~~~~~~~~~~~~~~~~进程间通信(Interprocess Communication, IPC)是指两个,或多个进程之间进行数据交换的过程.2. 进程间通信分类~~~~~~~~~~~~~~~~~1) 简单进程间通信:命令行参数.环境变量.信号.文件.2) 传统进程间通信:管道(fifo/pipe).3) XSI进程间通信:

进程通信和线程通信

Linux系统中的线程通信方式主要以下几种: *  锁机制:包括互斥锁.条件变量.读写锁 进程通信: 管道(PIPE):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系(父子进程)的进程间使用.另外管道传送的是无格式的字节流,并且管道缓冲区的大小是有限的(管道缓冲区存在于内存中,在管道创建时,为缓冲区分配一个页面大小). 有名管道 (FIFO): 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信. 信号(Signal): 信号是一种比较复杂的通信方式,用于通知接

Qt的内部进程通信机制 [转]

Qt 作为一种跨平台的基于 C++ 的 GUI系统,能够提供给用户构造图形用户界面的强大功能.自从 1996 年 Qt 被 Trolltech公司发布以来,该系统成为世界上很多成功的图形用户应用所使用的主要系统.更为重要的是,Linux 操作系统的桌面环境系统 KDE 也是基于 Qt构造的.目前,Qt 已经提供了对包括 MS/Windows.Unix/X11 和嵌入式平台的支持,得到了越来越广泛的应用. 在 Qt 系统中,不仅有着构造完善的系统结构,而且为了满足用户对编写图形用户界面应用的种种需

Linux系统编程@进程通信(一)

进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统的一个分支) POSIX进程间通信(POSIX:可移植操作系统接口,为了提高UNIX环境下应用程序的可移植性.很多其他系统也支持POSIX标准(如:DEC OpenVMS和Windows).) 现在Linux使用的进程间通信方式包括: 管道(pipe).有名管道(FIFO) 信号(signal) 消

Linux进程通信——管道

进程间通信(IPC:Inner Proceeding Communication) 进程是操作系统实现程序独占系统运行的假象的方法,是对处理器.主存.I/O设备的抽象表示.每个进程都是一个独立的资源管理单元,每个进程所看到的是自己独占使用系统的假象,因此各个进程之间是不能够直接的访问对方进程的资源的,不同的进程之间进行信息交互需要借助操作系统提供的特殊的进程通信机制. 进程之间的通信,从物理上分,可以分为同主机的进程之间的通信和不同主机间的进程之间的通信.从通信内容方式上分,可以分为数据交互.同

进程通信、线程同步 概述

进程通信.线程同步  概述 线程同步 CRITICAL_SECTION 临界区. 同一时刻只能由一个线程访问的资源,叫临界资源,比如打印机.访问临界资源的代码叫临界代码区域. CRITICAL_SECTION对象没有句柄,不能被其他线程共享. 线程同步之 CRITICAL_SECTION . http://blog.csdn.net/chuchus/article/details/24494253 MUTEX 互斥量. MUTEX对象有句柄,所以也可用于不同进程的线程之间做同步. MUTEX有超

Linux笔记--Linux进程通信

Linux进程间通信 文章来源: http://www.cnblogs.com/linshui91/archive/2010/09/29/1838770.html 一.进程间通信概述进程通信有如下一些目的:A.数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间B.共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到.C.通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程).D.