源地址:http://www.cnblogs.com/forstudy/archive/2012/03/26/2413724.html

Linux--进程间通信(信号量,共享内存)(转)

 

一. 信号量  

l信号量: 解决进程之间的同步与互斥的IPC机制

多个进程同时运行,之间存在关联
  •同步关系
  •互斥关系
互斥与同步关系存在的根源在于临界资源
  •临界资源是在同一个时刻只允许有限个(通常只有一个)进程可以访问(读)或修改(写)的资源
    –硬件资源(处理器、内存、存储器以及其他外围设备等)
    –软件资源(共享代码段,共享结构和变量等)
  •临界区,临界区本身也会成为临界资源
 
 
一个称为信号量的变量
  •信号量对应于某一种资源,取一个非负的整型值
  •信号量值指的是当前可用的该资源的数量,若它等于0则意味着目前没有可用的资源
在该信号量下等待资源的进程等待队列
对信号量进行的两个原子操作(PV操作)
  •P操作
  •V操作
 
最简单的信号量是只能取0 和1 两种值,叫做二维信号量
 
编程步骤:
  创建信号量或获得在系统已存在的信号量
    •调用semget()函数
    •不同进程使用同一个信号量键值来获得同一个信号量
  初始化信号量
    •使用semctl()函数的SETVAL操作
    •当使用二维信号量时,通常将信号量初始化为1
  进行信号量的PV操作
    •调用semop()函数
    •实现进程之间的同步和互斥的核心部分
  如果不需要信号量,则从系统中删除它
    •使用semclt()函数的IPC_RMID操作
    •在程序中不应该出现对已被删除的信号量的操作
 

 eg. 通过对信号量PV操作,消除父子进程间的竞争条件,使得其调用顺序可控。
 union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
}; // 将信号量sem_id设置为init_value
int init_sem(int sem_id,int init_value) {
union semun sem_union;
sem_union.val=init_value;
if (semctl(sem_id,,SETVAL,sem_union)==-) {
perror("Sem init");
exit();
}
return ;
}
// 删除sem_id信号量
int del_sem(int sem_id) {
union semun sem_union;
if (semctl(sem_id,,IPC_RMID,sem_union)==-) {
perror("Sem delete");
exit();
}
return ;
}
// 对sem_id执行p操作
int sem_p(int sem_id) {
struct sembuf sem_buf;
sem_buf.sem_num=;//信号量编号
sem_buf.sem_op=-;//P操作
sem_buf.sem_flg=SEM_UNDO;//系统退出前未释放信号量,系统自动释放
if (semop(sem_id,&sem_buf,)==-) {
perror("Sem P operation");
exit();
}
return ;
}
// 对sem_id执行V操作
int sem_v(int sem_id) {
struct sembuf sem_buf;
sem_buf.sem_num=;
sem_buf.sem_op=;//V操作
sem_buf.sem_flg=SEM_UNDO;
if (semop(sem_id,&sem_buf,)==-) {
perror("Sem V operation");
exit();
}
return ;
}
 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include "sem_com.c" #define DELAY_TIME 3 int main() {
pid_t pid;
// int sem_id;
// key_t sem_key; // sem_key=ftok(".",'a');
// 以0666且create mode创建一个信号量,返回给sem_id
// sem_id=semget(sem_key,1,0666|IPC_CREAT);
// 将sem_id设为1
// init_sem(sem_id,1); if ((pid=fork())<) {
perror("Fork error!\n");
exit();
} else if (pid==) {
// sem_p(sem_id); // P操作
printf("Child running...\n");
sleep(DELAY_TIME);
printf("Child %d,returned value:%d.\n",getpid(),pid);
// sem_v(sem_id); // V操作
exit();
} else {
// sem_p(sem_id); // P操作
printf("Parent running!\n");
sleep(DELAY_TIME);
printf("Parent %d,returned value:%d.\n",getpid(),pid);
// sem_v(sem_id); // V操作
// waitpid(pid,0,0);
// del_sem(sem_id);
exit();
} }

在以上程序注释//未去掉时,即没用信号量机制时,其结果为:

显然,此处存在竞争条件。

在以上程序注释//去掉后,即使用信号量机制,其结果为:

由于父子进程采用同一信号量且均执行各自PV操作,故必先等一个进程的V操作后,另一个进程才能工作。

二. 共享内存

 

最为高效的进程间通信方式
 
进程直接读写内存,不需要任何数据的拷贝
  •为了在多个进程间交换信息,内核专门留出了一块内存区
  •由需要访问的进程将其映射到自己私有地址空间
  •进程直接读写这一内存区而不需要进行数据的拷贝,提高了效率
 
多个进程共享一段内存,需要依靠某种同步机制,如互斥锁和信号量等

l共享内存编程步骤:
  1. 创建共享内存
    •函数shmget()
    •从内存中获得一段共享内存区域
 
  2. 映射共享内存
    •把这段创建的共享内存映射到具体的进程空间中
    •函数shmat()
 
  3. 使用这段共享内存
    •可以使用不带缓冲的I/O读写命令对其进行操作
 
  4. 撤销映射操作: 函数shmdt()
 
  5. 删除共享内存: 函数shctl()
 

eg. 下面这个例子完成:父进程从stdin读取字符串并保存到共享内存中,子进程从共享内存中读出数据并输出到stdout

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h> #define BUFFER_SIZE 2048 int main() {
pid_t pid;
int shmid;
char *shm_addr;
char flag[]="Parent";
char buff[BUFFER_SIZE];
// 创建当前进程的私有共享内存
if ((shmid=shmget(IPC_PRIVATE,BUFFER_SIZE,))<) {
perror("shmget");
exit();
} else
printf("Create shared memory: %d.\n",shmid); // ipcs 命令往标准输出写入一些关于活动进程间通信设施的信息
// -m 表示共享内存
printf("Created shared memory status:\n");
system("ipcs -m"); if((pid=fork())<) {
perror("fork");
exit();
}else if (pid==) {
// 自动分配共享内存映射地址,为可读可写,映射地址返回给shm_addr
if ((shm_addr=shmat(shmid,,))==(void*)-) {
perror("Child:shmat");
exit();
}else
printf("Child: Attach shared-memory: %p.\n",shm_addr); printf("Child Attach shared memory status:\n");
system("ipcs -m");
// 比较shm_addr,flag的长度为strlen(flag)的字符
// 当其内容相同时,返回0
// 否则返回(str1[n]-str2[n])
while (strncmp(shm_addr,flag,strlen(flag))) {
printf("Child: Waiting for data...\n");
sleep();
} strcpy(buff,shm_addr+strlen(flag));
printf("Child: Shared-memory: %s\n",buff);
// 删除子进程的共享内存映射地址
if (shmdt(shm_addr)<) {
perror("Child:shmdt");
exit();
}else
printf("Child: Deattach shared-memory.\n"); printf("Child Deattach shared memory status:\n");
system("ipcs -m"); }else{
sleep();
// 自动分配共享内存映射地址,为可读可写,映射地址返回给shm_addr
if ((shm_addr=shmat(shmid,,))==(void*)-) {
perror("Parent:shmat");
exit();
}else
printf("Parent: Attach shared-memory: %p.\n",shm_addr); printf("Parent Attach shared memory status:\n");
system("ipcs -m");
// shm_addr为flag+stdin
sleep();
printf("\nInput string:\n");
fgets(buff,BUFFER_SIZE-strlen(flag),stdin);
strncpy(shm_addr+strlen(flag),buff,strlen(buff));
strncpy(shm_addr,flag,strlen(flag));
// 删除父进程的共享内存映射地址
if (shmdt(shm_addr)<) {
perror("Parent:shmdt");
exit();
}else
printf("Parent: Deattach shared-memory.\n"); printf("Parent Deattach shared memory status:\n");
system("ipcs -m");
// 保证父进程在删除共享内存前,子进程能读到共享内存的内容
waitpid(pid,NULL,);
// 删除共享内存
if (shmctl(shmid,IPC_RMID,NULL)==-) {
perror("shmct:IPC_RMID");
exit();
}else
printf("Delete shared-memory.\n"); printf("Child Delete shared memory status:\n");
system("ipcs -m"); printf("Finished!\n");
} exit();
}

 
分类: Linux

转:Linux--进程间通信(信号量,共享内存)的更多相关文章

  1. Linux进程间通信—使用共享内存

    Linux进程间通信-使用共享内存 转自: https://blog.csdn.net/ljianhui/article/details/10253345 下面将讲解进程间通信的另一种方式,使用共享内 ...

  2. Linux进程间通信——使用共享内存

    一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存. ...

  3. Linux进程间通信——使用共享内存(转)

    一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存. ...

  4. Linux进程间通信(四) - 共享内存

    共享内存的优势 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只 ...

  5. linux进程间通信之共享内存篇

    本文是对http://www.cnblogs.com/andtt/articles/2136279.html中共享内存(上)的进一步阐释说说明 1 共享内存的实现原理 共享内存是linux进程间通讯的 ...

  6. linux进程间通信之共享内存学习记录

    进程 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed). 广义定义:进程是一个具有一定独立功能的 ...

  7. Linux进程间通信之共享内存

    一,共享内存  内核管理一片物理内存,允许不同的进程同时映射,多个进程可以映射同一块内存,被多个进程同时映射的物理内存,即共享内存.  映射物理内存叫挂接,用完以后解除映射叫脱接. 1,共享内存的特点 ...

  8. linux进程间通信同步-共享内存

    参考:https://www.cnblogs.com/charlesblc/p/6142868.html 使用有名信号量,sem_open().sem_close().sem_post().sem_w ...

  9. Linux进程间通信(消息队列/信号量+共享内存)

    写在前面 不得不说,Deadline果真是第一生产力.不过做出来的东西真的是不堪入目,于是又花了一早上重写代码. 实验内容 进程通信的邮箱方式由操作系统提供形如 send()和 receive()的系 ...

  10. Linux环境进程间通信(五): 共享内存(下)

    linux下进程间通信的几种主要手段: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允 ...

随机推荐

  1. import socketserver 模块 (27-03)

    使用socketserver实现并发聊天 服务端可以比喻做一部电话. ("127.0.0.1", 8000) 比喻做服务端的一个号码. 1,server.py import soc ...

  2. Bootstrap——设置Tab标签切换

    最近一个小项目需要用Tab标签切换显示不同div内容,用到了Bootstrap里面的东西,但是在Bootstrap3教程里却没有找到对应的代码,这里记录一下,方便以后快速查阅学习. 代码如下: < ...

  3. 【daydayup】ceshuChat

    时时当勉励,岁月不待人.珍惜时间伐~ 先看看项目运行的效果 这个是在本地环境打开了两个8080端口进行模拟运行的. 先放下作者的开源地址:https://github.com/ceshu/ceshuC ...

  4. php7 mysql_pconnect() 缺失 解决方法

    php7 兼容 MySQL 相关函数 PHP7 废除了 ”mysql.dll” ,推荐使用 mysqli 或者 pdo_mysql http://PHP.net/manual/zh/mysqlinfo ...

  5. [JZOJ4639] 【NOIP2016提高组A组7.16】Angel Beats!

    题目 描述 题目大意 给你一棵树,每次询问两个点,求出这两个点的子树的重心到其中每个点的距离和. 重心的定义是到其中每个点距离和最小的点(不一定在两棵子树内) 思考历程 想想以前我是怎么求重心的呢-- ...

  6. 【玲珑杯 round#18 A】计算几何你瞎暴力

    [Link]:http://www.ifrog.cc/acm/problem/1143?contest=1020&no=0 [Description] [Solution] 因为每个点的(xi ...

  7. Python-线程(1)

    目录 什么是线程 进程与线程的区别 开启线程 为什么要使用线程 线程之间数据是共享的 什么是线程 线程与进程都是虚拟单位,目的是为了更好的描述某种事物 进程与线程的区别 进程:资源单位 线程:执行单位 ...

  8. springboot与任务(定时任务)

    描述: 项目开发中经常需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息.Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor .TaskScheduler ...

  9. python dict 实现swich

    使用dict实现swich,通过不同的键映射不同的函数. swich = { 'hour1':pred.getper1htable, 'hour6':pred.getper6htable, 'hour ...

  10. VS2010-MFC(MFC应用程序框架分析)

    转自:http://www.jizhuomi.com/software/145.html 一.SDK应用程序与MFC应用程序运行过程的对比 程序运行都要有入口函数,在之前的C++教程中都是main函数 ...