源地址: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. P2528 [SHOI2001]排序工作量之新任务

    P2528 [SHOI2001]排序工作量之新任务 题目描述 假设我们将序列中第i件物品的参数定义为Ai,那么排序就是指将A1,…,An从小到大排序.若i<j且Ai>Aj,则<i ...

  2. Mybatis功能架构及执行流程

    原文地址:http://blog.51cto.com/12222886/2052647 一.功能架构设计 功能架构讲解: 我们把Mybatis的功能架构分为三层: (1) API接口层:提供给外部使用 ...

  3. c++ const的用法

    1.修饰成员变量 int value=0; int *p=&value; const int *p_c=&value;//指针指向常量,但是指针所指向的地址可以修改(int const ...

  4. 计算图像数据集的RGB均值

    最近在跑代码的时候,需要用到RGB三个通道上的均值,如下图所示: 写了一个程序,如下: import os import cv2 import random import numpy as np #数 ...

  5. ASCII专用测试字符串

    这段是废话: 在很多时候不同语言所写的不同终端中 经常会有字符串转码的问题 常用一下字符串测试不同终端的输出可以快速匹配和修改默认转码 正文: !""""#$% ...

  6. unity3d入门 Demo 学习记录

    闲来学习一下 unity3d 的Demo,记录如下. 官方 Demo,名字为 Roll-A-Ball,如图 场景比较简单,包含地面.玩家精灵.主摄像机.墙壁.可拾取的方块.分数为示 text.平行光源 ...

  7. 【核心核心】10.Spring事务管理【TX】XML+注解方式

    转账案例环境搭建 1.引入JAR包 IOC的6个包 AOP的4个包 C3P0的1个包 MySQL的1个驱动包 JDBC的2个目标包 整合JUnit测试1个包 2.引入配置文件 log4j.proper ...

  8. 第二章计算机网络ios 模型

    机构: ISO国际标准化组织: ITU国际电信联盟: ANSI 美国国家标准委员会: ECMA欧洲计算机制作商协会 ITEF因特网特别任务组. 协议:为计算机网路中进行数据交换而建立的规则,标准或约定 ...

  9. localhost与127.0.0.1区别

    一.连接MySQL数据库有两种方式:TCP/IP(一般理解的端口的那种)和Unix套接字(一般叫socket或者sock) 大部分情况下,可以用localhost代表本机127.,但是在MySQL连接 ...

  10. html+css简单的实现360搜索引擎首页面

    今天主要学习了是如何实现的,以及我在写这个页面的时候我所遇到的一些困难. 主要实现是用代码的,不说废话了,其实我是想说我走的坑有哪些. 1.代码的基础不好,元素的一些属性不熟悉,对于HTML和css还 ...