国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

進程間通信之信號量機制+代碼實例

2019-11-08 18:20:57
字體:
來源:轉載
供稿:網友

信號量: 一、什么是信號量 為了防止出現因多個程序同時訪問一個共享資源而引發的一系列問題,我們需要一種方法,它可以通過某種方法,在任一時刻只能有一個執行進程訪問代碼的臨界區域。臨界區域是一種互斥資源。而信號量就可以提供這樣的一種訪問機制,讓一個臨界區同一時間只有一個進程在訪問它,也就是說信號量是用來調協進程對共享資源的訪問的。

信號量是一個特殊的變量,相當于一個計數器。程序對其訪問都是原子操作,且只允許對它進行等待(即P(信號變量))和發送(即V(信號變量))信息操作。

常見的信號量形式為二元信號量,最簡單的信號量是只能取0和1的變量。而可以取多個正整數的信號量被稱為通用信號量。這里主要討論二進制信號量。它控制單個資源,一般來講,信號量的初始值可以是任意一個正值,該值表示公有多少個共享資源單位可供共享應用。 信號量有下面的一些特性: (1)信號量并非是單個非負值,而必需定義一個含有一個或者多個信號量值的集合。當創建信號量時,要指定集合中信號量值的數量。 信號的 (2)信號量的創建獨立于它的初始化,這就導致不能原子的創建一個信號量集合,當然,我們可以用編程的手段很容易的避免。 (3)信號量的生命周期是隨內核的,所以可能造成死鎖的可能性(一個進程獲得臨界資源,拿到了信號量的鎖,然后非正常原因掛掉,那么其它的進程也不能利用臨界資源了)。 這種可能行的存在會帶來很糟糕的影響,而undo功能就是為了解決這個糟糕的情況的。 在信號量中,函數semop是自動執行信號量集上的操作數組。函數原型如下:

#incldue<sys/sem.h>int semop(int semid, struct sembuf semoparray[], size_t nops);//返回值:若成功,返回0;若出錯,返回-1

參數semparry是一個指針,它指向一個由sembuf結構表示的信號量操作數組

struct sembuf{ unsigned short sem_num; short sem_op; short sem_flg; }

函數semop中參數的意義代表:nops規定該數組中操作的數量(元素個數) 而對集合中每個成員的操作有相應的sem_op來決定。此值可負可正可零。而undo標志對應于相應的sem_flg成員的SEM_UNDO位。 (1)若sem_op為正值,就是進程釋放的占用資源數,sem_op值會增加到信號量上,即可操作V操作。如果指定了undo標志,則也可以從該進程此信號量值上減去sem_op (2)若sem_op是負數值,則表示要獲取由該信號量控制的資源數。 如果指定了undo標志,則sem_op的絕對值也可以加到該信號量調整值上。 總結:無論何時只要為信號量操作指定了SEM_UNDO標志,然后分配資源,那么內核就會記住對于該信號量,分配給調用進程多少資源,程序結束時(不論正常或不正常),保證信號值會被重設為semop()調用前的值。這樣做的目的在于避免程序在異常情況下結束時未將鎖定的資源解鎖,造成該資源永遠鎖定。 下面介紹有關信號量的一些相關函數 1、semget函數 它的作用是創建一個新信號量或取得一個已有信號量,原型為:

#include<sys/sem.h>int semget(key_t key, int num_sems, int sem_flags);

第一個參數key:相當于一個標識符,一般由ftok函數來產生。 第二個參數:num_sems指定需要的信號量數目,它的值幾乎總是1。

第三個參數sem_flags:是一組標志,當想要當信號量不存在時創建一個新的信號量,可以和值ipC_CREAT做按位或操作。設置了IPC_CREAT標志后,即使給出的鍵是一個已有信號量的鍵,也不會產生錯誤。而IPC_CREAT | IPC_EXCL則可以創建一個新的,唯一的信號量,如果信號量已存在,返回一個錯誤。 2、semctl函數 該函數用來直接控制信號量信息,可以通過標志來銷毀信號量。它的原型為:

#include<sys/sem.h>int semctl(int sem_id, int sem_num, int command, ...);

第四個參數是可選的,是否使用取決于所請求的命令,如果使用該參數,一般類型是

union semun{ int val; struct semid_ds *buf; unsigned short *arry; };

前兩個參數與前面一個函數中的一樣,command通常是下面兩個值中的其中一個 SETVAL:用來把信號量初始化為一個已知的值。p 這個值通過union semun中的val成員設置,其作用是在信號量第一次使用前對它進行設置。 IPC_RMID:用于刪除一個已經無需繼續使用的信號量標識符。 3、函數semop() 此函數前文已經提過。 源代碼如下:

//編寫Makefilebin=test_semcc=gccsrc=comm.c test_sem.c$(bin):$(src) $(cc) -o $@ $^.PHONY:cleanclean: rm -f $(bin)//編寫comm.h#ifndef __COMM_#define __COMM_#include <stdio.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/sem.h>#include<string.h>#include<error.h>#define PATHNAME "."#define PROJID 0x666union semun { int val; struct semid_ds *buf; unsigned short *arry; }; int creatSemset(int nums);int initSem(int semid, int which);int getSemset(int nums);int P(int semid, int which);int V(int semid, int which);int destorySemset(int semid);#endif//編寫comm.c#include "comm.h"static int commSemset(int nums,int flags){ key_t _k = ftok(PATHNAME, PROJID); if(_k < 0) { perror("ftok"); return -1; } int semid=semget(_k,nums,flags); if(semid<0) { perror("semget"); return -2; } return semid;}static int sem_op(int semid, int which, int op)//操作信號量{ struct sembuf s; s.sem_num = which; s.sem_op = op; s.sem_flag = 0; int ret = semop(semid, &s, 1)//調用 if(ret < 0) { perro("semop"); return -1; } return ret;}int initSemSet(int semid,int which){ union SemUn Un; Un.val=1; int ret=semctl(semid,which,SETVAL,Un);// if(ret<0) { perror("semctl"); return -1; } return 0;}int creatSemset(int nums)//創建信號量{ int flags=IPC_CREAT | IPC_EXCL | 0666; return commSemset(nums,flags);}int getSemset(int nums){ return commSemset(0,0);}int P(int semid, int which)//p操作{ return semop(semid, which, -1);}int V(int semid, int which)//V操作{ return semop(semid, which, 1);}int destorySemset(int semid)//銷毀信號量{ int ret = semctl(semid, 0, IPC_RMID); if(ret<0) { perror("semctl"); return -1; } return 0; }test_sem.c//sem.c#include "comm.h"int main(){ int semid=creatSemSet(1); initSemSet(semid,0); pid_t id=fork(); if(id==0) { int semid=getSemSet(); while(1) { P(semid,0); //進入臨界區 printf("A"); fflush(stdout); usleep(10031); printf("A"); fflush(stdout); usleep(10021); V(semid,0);//釋放 } } else { while(1) { P(semid,0); //進入臨界區 printf("B"); fflush(stdout); usleep(10051); printf("B"); fflush(stdout); usleep(10003); V(semid,0);//釋放 } } destorySemSet(semid);}
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 古蔺县| 通辽市| 红原县| 桦川县| 兴业县| 常熟市| 通山县| 新竹县| 永吉县| 曲沃县| 镇沅| 泊头市| 台南市| 崇左市| 罗江县| 井研县| 抚顺市| 龙陵县| 巴彦县| 石泉县| 霍林郭勒市| 同江市| 嵊泗县| 林州市| 桃江县| 衡南县| 兖州市| 金堂县| 白朗县| 东乡族自治县| 六枝特区| 德令哈市| 玉树县| 大余县| 时尚| 静安区| 乾安县| 扎兰屯市| 柘城县| 九江县| 凌云县|