当前位置:网站首页>【进程间通信】信号量的使用/共享内存
【进程间通信】信号量的使用/共享内存
2022-08-02 14:13:00 【白U】
信号量:
:特殊的变量 值 > 0 减1 代表获取资源 p操作 (会阻塞)
加1 代表释放资源,v操作 (会阻塞)
作用 : 同步进程 (程序的红绿灯,控制对进程对某个资源的访问)
临界资源:同一时刻,只允许一个进程访问的资源
临界区:访问临界资源的代码段
帮助手册 man semget;(信号量)man semctl(封装)信号量是由内核控制的。不受A/B进程的控制
semget()
创建/获取一个已存在的信号量
//A 创建好信号量(需要初始化信号量semget---semctl()
) ,B只需要加入(无需再初始化semget()
获取信号量)semop()
p,v 修改信号量semctl()
初始化,删除信号量 (初始值为1,表明资源空闲)
sem_init()// semget—semctl(),emget()
sem_p()// semop() -1
sem_v()// semop() +1
sem_destory() semctl()
引用头文件:
#include <sys/sem.h>
//创建和获取信号量
//key 相当于信号量的标识,如果使用同一个key,就是在使用同一个信号量
int semget(key_t key, int nsems, int semflg); / // 整数值 //创建信号量个数 //如文件的权限
//可以创建一组信号量,只是创建了一个而已 IPC_CRET|IPC_EXCL|0600
//如果创建失败,两种情况(信号量已存在,(semget()获取即可,或 创建失败)
//如果创建成功,接下来
//初始化信号量
int semctl(int semid, int semnum, int cmd, ...);
//semnum:第几(第一个0)个信号(可以创建一组(多个 )可以分别初始化
//cmd 命令(SETVAL) (IPC_RMID)
// ... 联合体(给SETVAL赋值)
semctl(semid,0,SETVAL,a) //给信号量赋值
semctl(semid,0,IPC_RMID) //删除信号量
int val; /Value for SETVAL; (给信号量赋值)
union semun//联合体
{
**int val; /Value for SETVAL; (给信号量赋值)**
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
};
使用 union semun 联合体给信号量赋值
union semun a;
a.val = 1;
// 对信号量的处理
int semop(int semid, struct sembuf *sops, size_t nsops);
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg = SEM_UNDO; /* operation flags */ //p操作后,当程序异常终止,可以自动执行V操作
例如:创建a.c / b.c文件
信号量文件 sem.c
头文件:
- sem.h文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sem.h>
union semun
{
int val;
};
void sem_init();
void sem_p();
void sem_v();
void sem_destroy();
- sem.c文件
#include "sem.h"
static int semid = -1;
void sem_init()
{
semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);
if ( semid == -1 )//全新创建失败,可能已存在
{
semid = semget((key_t)1234,1,0600);
if ( semid == -1 )
{
printf("create sem failed\n");
}
}
else//全新创建成功,初始化
{
union semun a;
a.val = 1;
if ( semctl(semid,0,SETVAL,a) == -1 )
{
printf("semctl setval failed\n");
}
}
}
void sem_p()
{
struct sembuf a;
a.sem_num = 0;
a.sem_op = -1;//p
a.sem_flg = SEM_UNDO;
if( semop(semid,&a,1) == -1 )
{
printf("semop p failed\n");
}
}
void sem_v()
{
struct sembuf a; //处理信号量
a.sem_num = 0; //表示第1个信号量
a.sem_op = 1;//给信号量赋值
a.sem_flg = SEM_UNDO; //表示如果p操作后,程序异常结束,可以自动执行v操作,释放资源。
if( semop(semid,&a,1) == -1 ) //判断V操作是否成功
{
printf("semop v failed\n");
}
}
void sem_destroy()
{
if ( semctl(semid,0,IPC_RMID) == -1 )
{
printf("destroy failed\n");
}
}
- a.c 文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "sem.h"
int main()
{
sem_init();
for( int i = 0; i < 5; i++ )
{
sem_p();
printf("A");
fflush(stdout);
int n = rand() % 3;
sleep(n);
printf("A");
fflush(stdout);
sem_v();
n = rand() % 3;
sleep(n);
}
sleep(10);
sem_destroy();
exit(0);
}
- b.c文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "sem.h"
int main()
{
sem_init();
for( int i = 0; i < 5; i++ )
{
sem_p();
printf("B");
fflush(stdout);
int n = rand() % 3;
sleep(n);
printf("B");
fflush(stdout);
sem_v();
n = rand() % 3;
sleep(n);
}
}
编译命令:
gcc -c sem.c
gcc -o a a.c sem.c
gcc -o b b.c sem.c
执行: ./a& ./b&
(表示在后台同时执行)
当结束进程,使用ipcs
命令查看是否将a.c 和b.c均结束
如果没有使用ipcrm
手动结束。防止下次执行出现异常。(除非关机重启,负责未删除的信号量一直在)
信号量学习主要了解使用信号量的过程,
初始化,
p操作
v操作
删除信号量
共享内存
- 多个进程共享同一块物理内存。
(先开辟一块物理内存,多个进程将其映射到自己的虚拟地址空间,如果有一个进程修改此内存上的内容,其他共享的进程也会立刻看到。)
但是没有提供同步机制,需要信号量来控制进程的同步
。
定义两个信号量:
目的:保证在读端没有写数据的时候,只允许写端写一次数据。
(实现管道的功能)
- sem.h
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/sem.h>
#define SEM1 0
#define SEM2 1
#define SEM_MAX 2
union semun
{
int val;
};
void sem_init();
void sem_p();
void sem_v();
void sem_destroy();
- sem.c
#include "sem.h"
static int semid = -1;
void sem_init()
{
//创建信号量 //最多创建
semid = semget((key_t)1234,SEM_MAX,IPC_CREAT|IPC_EXCL|0600);
if ( semid == -1 )//全新创建失败,可能已存在
{
//获取信号量
semid = semget((key_t)1234,SEM_MAX,0600);
if ( semid == -1 )
{
printf("create sem failed\n");
}
}
else//全新创建成功,初始化
{
union semun a;
int arr[SEM_MAX] = {
1,0}; //两个信号量,初始值分别为1,0
for( int i = 0; i < SEM_MAX; i++ )
{
a.val = arr[i]; //给信号量赋值,控制信号量,成功返回0
if ( semctl(semid,i,SETVAL,a) == -1 )
{
// i:给哪个信号量赋值
printf("semctl setval failed\n");
}
}
}
}
void sem_p(int index)
{
//用输入的index来控制不同信号量
if ( index < 0 || index >= SEM_MAX )
{
return;
}
struct sembuf a;
a.sem_num = index;
a.sem_op = -1;//p
a.sem_flg = SEM_UNDO;
if( semop(semid,&a,1) == -1 )
{
printf("semop p failed\n");
}
}
void sem_v(int index)
{
if ( index < 0 || index >= SEM_MAX )
{
return;
}
struct sembuf a;
a.sem_num = index;
a.sem_op = 1;//v
a.sem_flg = SEM_UNDO;
if( semop(semid,&a,1) == -1 )
{
printf("semop v failed\n");
}
}
void sem_destroy()
{
if ( semctl(semid,0,IPC_RMID) == -1 )
{
printf("destroy failed\n");
}
}
- 对两个信号量的处理:(S1 S2)
else//全新创建成功,初始化
{
union semun a;
int arr[SEM_MAX] = {1,0}; //两个信号量,初始值分别为1,0
for( int i = 0; i < SEM_MAX; i++ )
{
a.val = arr[i]; //给信号量赋值,控制信号量,成功返回0
if ( semctl(semid,i,SETVAL,a) == -1 )
{ // i:给哪个信号量赋值
printf(“semctl setval failed\n”);
} - test.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#include "sem.h"
int main()
{
int shmid = shmget((key_t)1234,128,IPC_CREAT|0600);
if ( shmid == -1 )
{
exit(1);
}
char * s = (char*)shmat(shmid,NULL,0);
if ( s == (char*)-1 )
{
exit(1);
}
sem_init();
while( 1 )
{
sem_p(SEM2);
if ( strncmp(s,"end",3) == 0 )
{
break;
}
printf("read:%s\n",s);
sem_v(SEM1);
}
shmdt(s);
sem_destroy(); //在读操作结束后 销毁信号量
exit(0);
}
//在读操作结束后 销毁信号量
- main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#include "sem.h"
int main()
{
//创建共享内存 key:标识 size: 128
int shmid = shmget((key_t)1234,128,IPC_CREAT|0600);
if ( shmid == -1 )
{
exit(1);
}
//将申请的物理内存映射到进程的虚拟地址空间中
//若映射成功,返回共享内存的首地址,否则返回空
char* s = (char*)shmat(shmid,NULL,0);
if ( s == (char*)-1 )
{
exit(1);
}
sem_init();
while( 1 )
{
printf("input\n");
char buff[128] = {
0};
//键盘获取数据
fgets(buff,128,stdin);
sem_p(SEM1);
//(读操作) 将获取的数据,复制到共享内存中
strcpy(s,buff);
sem_v(SEM2);
//结束
if ( strncmp(buff,"end",3) == 0 )
{
break;
}
}
//断开映射
shmdt(s);
exit(0);
}
p77《linux平台开发》
作业:
a进程只输出a
b进程只输出b
c进程只输出c
打印结果 abcabcabc…
边栏推荐
猜你喜欢
Codeforces Round #605 (Div. 3)
Based on the matrix calculation in the linear regression equation of the coefficient estimates
第三十三章:图的基本概念与性质
[System Design and Implementation] Flink-based distracted driving prediction and data analysis system
2.登录退出,登录状态检查,验证码
二叉树的遍历:递归法/ 迭代法/ 统一迭代法(强QAQ)
光导布局设计工具
6. Unified logging
第三十章:普通树的存储和遍历
unity-shader(中级)
随机推荐
饥荒联机版Mod开发——配置代码环境(二)
audio console无法连接到RPC服务
Optisystem应用:光电检测器灵敏度建模
线性结构,顺序结构
Unity-Ads广告插件
企业的电子签名、私钥签名
远程连接Ubuntu中的Mysql
嵌入式学习硬件篇------初识ARM
1.开发社区首页,注册
动态数组-vector
5. Transaction management
Evaluation multipath weswood congestion control on ns3
Based on the least squares linear regression equation coefficient estimation
2021-06-06
软件测试基础知识(背)
光导布局设计工具
灵活的区域定义
光波导的入射耦合和出射耦合区域
第二十六章:二维数组
Server-Sent Events 一种轻量级的Push方式