一:首先我们先了解几个概念
1.临界资源: | 同一时间只能被一个进程或者一个线程访问的资源。 |
2.临界区: | 访问临界资源的代码区域。 |
3.原子操作: | 不可被中断的操作,一旦开始执行,只能到其结束。 常见的有P操作,和V操作。 |
4.进程同步: | 指为完成某种任务而建立的两个和多个进程,这些进程在合作的过程中需要协调工作次序进行有序的访问而出现等待所产生的制约关系。 |
5.进程异步: | 协调无等待。这两者是进程间的运行关系, |
6.阻塞运行: | 正在进行的进程由于发生某事件而暂时无法继续执行时 |
7.非阻塞运行: | 这两者是进程的运行状态。 |
二:再来了解以下几个问题
1.什么叫做信号量?信号量的实质是什么?
它与(管道,FIFO,以及消息队列)不同,它是一个计数器,用于多进程对共享对象的访问。--进程同步控制。
2.信号量的作用?
它是用来协调不同进程的数据对象的,而主要的应用是共享内存方式的进程间通信。本质上它是一个计数器,用来记录对某个资源(如共享内存)的存取状况,并且只有两个操作可以改变他们的值(P 和 V 操作)。
三:信号量的系统调用函数
1.系统调用函数semget()
函数头文件 及 函数原型: | #include<sys/sem.h> int semget( key_t key , int nsems , int flag ); | ||||||||||||
函数功能: | 创建一个新的信号量集,或者获取一个已经存在信号量集。
| ||||||||||||
参数介绍: |
| ||||||||||||
返回错误errno |
| ||||||||||||
信号量的一些相关值: |
|
2.信号量的控制semctl()
函数头文件 及 函数原型 | #include<sys/sem.h> int semctl ( int semid , int semnum , int cmd , ... /* union semun arg */); | ||||||||||||||
参数介绍: |
| ||||||||||||||
功能: | semctl函数会依据command参数返回不同的值,他的一个重要的用途就是为信号量赋初值,因为进程违法直接对信号量进行修改。 |
3.信号量操作semop函数
函数原型: | int semop(int semid,struct sembuf semoparray[], size_t nops); | ||||||||||||
函数功能: | 在Linux下,PV操作通过调用semop函数来实现,也只有他能对PV进行操作 | ||||||||||||
参数介绍: |
| ||||||||||||
函数返回值: | 成功返回0,失败返回-1, errno解析:
|
sem_flg用来告诉系统当前进程退出时自动还原操作,它维护着一个整形变量semadj(信号量的计数器),可设置为IPC_NOWAIT或SEM_UNDO两种状态。只有将sem_flg指定为SEM_UNDO标志后,semadj(所指定信号量针对调用进程的调整值才会更新,即减去sem_num的值。此外如果此操作指定SEM_UNDO,系统更新过程中会撤销此信号量的计数(semadj)。此操作可以随时进行——-他永远不会强制等待的过程。调用进程必须有改变信号量集的权限。
代码展示:
//sem.h文件
#ifndef _SEM_H
#define _SEM_H
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<fcntl.h>
typedef union semun
{
int val;
}semun;
int sem_init(int key);
void sem_p(int id,int sem);
void sem_v(int id,int sem);
void sem_del(int id);
#endif
//sem.c文件
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include"sem.h"
int sem_init(int key)
{
int semid = semget((key_t)key,0,0666);//获取
if(semid == -1)
{
semid = semget((key_t)key,1,0666|IPC_CREAT);//创建
semun un;
un.val = 0;//给信号量的初始值,根据需求定制
semctl(semid,0,SETVAL,un);//初始化
}
return semid;
}
void sem_p(int id,int sem)
{
struct sembuf buf;
buf.sem_num = sem;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
semop(id,&buf,1);
}
void sem_v(int id,int sem)
{
struct sembuf buf;
buf.sem_num = sem;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
semop(id,&buf,1);
}
void sem_del(int id)
{
semctl(id,0,IPC_RMID);
}