用信号量为共享内存添加同步机制

进程间通信的方式中,我们将多个进程共享同一块存储区来进行数据交换的方式称为共享内存通信。源于它直接将“内存”共享的特殊机制,它成为最快的一种IPC通信方式;然而它也不完美,它虽快,但是没有同步机制;通常在一个服务进程对共享存储区还未完成写操作之前,客户进程是不应当去取这些数据的,可没了同步,那可就乱了套了。

这种情况不是我们所愿意看到的,所以基于此 我们常常需要为用到的共享内存段添加上同步的机制,使之“完美”起来。通常呢,实现同步我们很自然地会想到信号量,是的,这里我就是这么干的。用基于信号量的PV操作实现完成一个带同步机制的共享内存段,这样它就可以像一个“fifo”队列一样了,并且它传输效率还会表现得非常不错,虽然它还比较简陋~。

信号量及相关函数

--------------------------------------------------------------------------------

先来说说用到的信号量及处理函数吧。信号量和其它的IPC结构(前面总结过管道、消息队列)不同。它本质就是一个计数器,用于为多个进程提供对共享数据对象的访问。通常进程为了获得共享的资源,需要执行以下操作:

①测试控制该资源的信号量

②若此信号量>0,则进程可以使用该资源。此种情况下,进程会将信号量值减1,表明它使用了一个资源单位。

③否则,此信号量的值为0,则使该进程进入休眠状态,直至信号量值>1。如果有进程正在休眠状态等待此信号量,则唤醒它们

还有就是为了正确的实现信号量,信号量值的测试及减1操作还应当是原子的。为此,信号量通常是在内核中实现的。一般而言,信号量初值可以是任意一个正值,该值表明有多少个共享资源单位可供共享应用。然而遗憾的是,这里我用到的XSI信号量也是有缺陷的。

这源于①信号量并非是单个非负值,它被定义为一个可能含有多个信号量值的集合。通常在创建信号量的时候,对该集合中信号量数量进行指定 ②信号量创建独立于它的初始化。这是最致命的,因为这将导致的是不能原子的创建一个信号量集合,并对该集合中的各个信号量值赋初值。③有的程序1在终止时可能并没有释放掉已经分配给它的信号量。

而对于信号处理函数通常有3个,首先是

1.semget函数

作用:创建一个新的信号量或取得一个已有的信号量

原型:int semget(key_t key, int nsems, int semflg)

参数:

int nsems  //它代表信号量集合中有多少个信号量。如果是创建新集合,则必须指定它;如果是引用现有的信号集(通常客户进程中),则将其指定为0.

int semflg  //和前面IPC机制类似,用来初始化信号集维护的semid_ds结构中的ipc_perm结构成员sem_perm。通常用IPC_CREAT|0644创建,要直接打开已存在的话 也直接填0就好

2.semctl函数

用途:该函数用来直接控制信号量信息.也就是直接删除信号量或者初始化信号量.

原型:int semctl(int semid, int semnum, int cmd, ...)

参数:

  int semid    //semget函数返回的信号量标识符.  

  int semnum,  //它代表要给该信号量集中的第几个信号量设置初值

  int cmd   //通常用SETVAL/GETVAL设置和获取信号量集中的一个单独的信号量。具体还有

IPC_STAT //读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。

IPC_SET  //设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
IPC_RMID  //将信号量集从内存中删除。
 
GETALL  //用于读取信号量集中的所有信号量的值。

GETNCNT  //返回正在等待资源的进程数目。

GETPID  //返回最后一个执行semop操作的进程的PID。

GETVAL  //返回信号量集中的一个单个的信号量的值。

GETZCNT  //返回这在等待完全空闲的资源的进程数目。

SETALL  //设置信号量集中的所有的信号量的值。

SETVAL  //设置信号量集中的一个单独的信号量的值

cmd的种类

如果有第四个参数,取决于所请求的命令,如果使用该参数,它通常是一个union semum结构,定义如下:

union semun
{   
    int val;    /* Value for SETVAL */通常就要它就够了
    struct semid_ds *buf;   
    unsigned short *arry;   
}; 
赋值形式:semun.val = 2  //初值放在val中

执行PV操作

3.semop函数

用途:用来改变信号量的值,该函数是具有原子性的。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/90042d57dd40cc272c9826cdc5d6cf2f.html