導航:首頁 > 網路營銷 > 函數semgetvalue

函數semgetvalue

發布時間:2021-02-25 04:52:41

1、創建兩個進程,一個向另一個進程發送一個字元串。

linux中的進程通信分為三個部分:低級通信,管道通信和進程間通信IPC(inter process communication)。linux的低級通信主要用來傳遞進程的控制信號——文件鎖和軟中斷信號機制。linux的進程間通信IPC有三個部分——①信號量,②共享內存和③消息隊列。以下是我編寫的linux進程通信的C語言實現代碼。操作系統為redhat9.0,編輯器為vi,編譯器採用gcc。下面所有實現代碼均已經通過測試,運行無誤。

一.低級通信--信號通信

signal.c

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

/*捕捉到信號sig之後,執行預先預定的動作函數*/
void sig_alarm(int sig)
{
printf("---the signal received is %d. /n", sig);
signal(SIGINT, SIG_DFL); //SIGINT終端中斷信號,SIG_DFL:恢復默認行為,SIN_IGN:忽略信號
}

int main()
{
signal(SIGINT, sig_alarm);//捕捉終端中斷信號
while(1)
{
printf("waiting here!/n");
sleep(1);
}
return 0;
}

二.管道通信

pipe.c

#include <stdio.h>
#define BUFFER_SIZE 30

int main()
{
int x;
int fd[2];
char buf[BUFFER_SIZE];
char s[BUFFER_SIZE];
pipe(fd);//創建管道
while((x=fork())==-1);//創建管道失敗時,進入循環

/*進入子進程,子進程向管道中寫入一個字元串*/
if(x==0)
{
sprintf(buf,"This is an example of pipe!/n");
write(fd[1],buf,BUFFER_SIZE);
exit(0);
}

/*進入父進程,父進程從管道的另一端讀出剛才寫入的字元串*/
else
{
wait(0);//等待子進程結束
read(fd[0],s,BUFFER_SIZE);//讀出字元串,並將其儲存在char s[]中
printf("%s",s);//列印字元串
}
return 0;
}

三.進程間通信——IPC

①信號量通信

sem.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

/*聯合體變數*/
union semun
{
int val; //信號量初始值
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};

/*函數聲明,信號量定義*/
static int set_semvalue(void); //設置信號量
static void del_semvalue(void);//刪除信號量
static int semaphore_p(void); //執行P操作
static int semaphore_v(void); //執行V操作
static int sem_id; //信號量標識符

int main(int argc, char *argv[])
{
int i;
int pause_time;
char op_char = 'O';
srand((unsigned int)getpid());
sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);//創建一個信號量,IPC_CREAT表示創建一個新的信號量

/*如果有參數,設置信號量,修改字元*/
if (argc > 1)
{
if (!set_semvalue())
{
fprintf(stderr, "Failed to initialize semaphore/n");
exit(EXIT_FAILURE);
}
op_char = 'X';
sleep(5);
}
for(i = 0; i < 10; i++)
{

/*執行P操作*/
if (!semaphore_p())
exit(EXIT_FAILURE);
printf("%c", op_char);
fflush(stdout);
pause_time = rand() % 3;
sleep(pause_time);
printf("%c", op_char);
fflush(stdout);

/*執行V操作*/
if (!semaphore_v())
exit(EXIT_FAILURE);
pause_time = rand() % 2;
sleep(pause_time);
}
printf("/n%d - finished/n", getpid());
if (argc > 1)
{
sleep(10);
del_semvalue(); //刪除信號量
}
exit(EXIT_SUCCESS);
}

/*設置信號量*/
static int set_semvalue(void)
{
union semun sem_union;
sem_union.val = 1;
if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
return(0);

return(1);
}

/*刪除信號量*/
static void del_semvalue(void)
{
union semun sem_union;
if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
fprintf(stderr, "Failed to delete semaphore/n");
}

/*執行P操作*/
static int semaphore_p(void)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1; /* P() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed/n");
return(0);
}
return(1);
}

/*執行V操作*/
static int semaphore_v(void)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1; /* V() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_v failed/n");
return(0);
}
return(1);
}

②消息隊列通信

send.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAX_TEXT 512

/*用於消息收發的結構體--my_msg_type:消息類型,some_text:消息正文*/
struct my_msg_st
{
long int my_msg_type;
char some_text[MAX_TEXT];
};

int main()
{
int running = 1;//程序運行標識符
struct my_msg_st some_data;
int msgid;//消息隊列標識符
char buffer[BUFSIZ];

/*創建與接受者相同的消息隊列*/
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d/n", errno);
exit(EXIT_FAILURE);
}

/*向消息隊列中發送消息*/
while(running)
{
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);
if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1)
{
fprintf(stderr, "msgsnd failed/n");
exit(EXIT_FAILURE);
}
if (strncmp(buffer, "end", 3) == 0)
{
running = 0;
}
}
exit(EXIT_SUCCESS);
}

receive.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

/*用於消息收發的結構體--my_msg_type:消息類型,some_text:消息正文*/
struct my_msg_st
{
long int my_msg_type;
char some_text[BUFSIZ];
};

int main()
{
int running = 1;//程序運行標識符
int msgid; //消息隊列標識符
struct my_msg_st some_data;
long int msg_to_receive = 0;//接收消息的類型--0表示msgid隊列上的第一個消息

/*創建消息隊列*/
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1)
{
fprintf(stderr, "msgget failed with error: %d/n", errno);
exit(EXIT_FAILURE);
}

/*接收消息*/
while(running)
{
if (msgrcv(msgid, (void *)&some_data, BUFSIZ,msg_to_receive, 0) == -1)
{
fprintf(stderr, "msgrcv failed with error: %d/n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s", some_data.some_text);
if (strncmp(some_data.some_text, "end", 3) == 0)
{
running = 0;
}
}

/*刪除消息隊列*/
if (msgctl(msgid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "msgctl(IPC_RMID) failed/n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

③共享內存通信

share.h

#define TEXT_SZ 2048 //申請共享內存大小
struct shared_use_st
{
int written_by_you; //written_by_you為1時表示有數據寫入,為0時表示數據已經被消費者提走
char some_text[TEXT_SZ];
};

procer.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "share.h"

int main()
{
int running = 1; //程序運行標志位
void *shared_memory = (void *)0;
struct shared_use_st *shared_stuff;
char buffer[BUFSIZ];
int shmid; //共享內存標識符

/*創建共享內存*/
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);
if (shmid == -1)
{
fprintf(stderr, "shmget failed/n");
exit(EXIT_FAILURE);
}

/*將共享內存連接到一個進程的地址空間中*/
shared_memory = shmat(shmid, (void *)0, 0);//指向共享內存第一個位元組的指針
if (shared_memory == (void *)-1)
{
fprintf(stderr, "shmat failed/n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X/n", (int)shared_memory);
shared_stuff = (struct shared_use_st *)shared_memory;

/*生產者寫入數據*/
while(running)
{
while(shared_stuff->written_by_you == 1)
{
sleep(1);
printf("waiting for client.../n");
}
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
strncpy(shared_stuff->some_text, buffer, TEXT_SZ);
shared_stuff->written_by_you = 1;
if (strncmp(buffer, "end", 3) == 0)
{
running = 0;
}
}

/*該函數用來將共享內存從當前進程中分離,僅使得當前進程不再能使用該共享內存*/
if (shmdt(shared_memory) == -1)
{
fprintf(stderr, "shmdt failed/n");
exit(EXIT_FAILURE);
}
printf("procer exit./n");
exit(EXIT_SUCCESS);
}

customer.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "share.h"

int main()
{
int running = 1;//程序運行標志位
void *shared_memory = (void *)0;
struct shared_use_st *shared_stuff;
int shmid; //共享內存標識符
srand((unsigned int)getpid());

/*創建共享內存*/
shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);
if (shmid == -1)
{
fprintf(stderr, "shmget failed/n");
exit(EXIT_FAILURE);
}

/*將共享內存連接到一個進程的地址空間中*/
shared_memory = shmat(shmid, (void *)0, 0);//指向共享內存第一個位元組的指針
if (shared_memory == (void *)-1)
{
fprintf(stderr, "shmat failed/n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X/n", (int)shared_memory);
shared_stuff = (struct shared_use_st *)shared_memory;
shared_stuff->written_by_you = 0;

/*消費者讀取數據*/
while(running)
{
if (shared_stuff->written_by_you)
{
printf("You wrote: %s", shared_stuff->some_text);
sleep( rand() % 4 );
shared_stuff->written_by_you = 0;
if (strncmp(shared_stuff->some_text, "end", 3) == 0)
{
running = 0;
}
}
}

/*該函數用來將共享內存從當前進程中分離,僅使得當前進程不再能使用該共享內存*/
if (shmdt(shared_memory) == -1)
{
fprintf(stderr, "shmdt failed/n");
exit(EXIT_FAILURE);
}

/*將共享內存刪除,所有進程均不能再訪問該共享內存*/
if (shmctl(shmid, IPC_RMID, 0) == -1)
{
fprintf(stderr, "shmctl(IPC_RMID) failed/n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}

2、用信號量描述象棋的執行

信號量(Semaphore),有時被稱為信號燈,是在多線程環境下使用的一種設施,是可以用來保證兩個或多個關鍵代碼段不被並發調用。在進入一個關鍵代碼段之前,線程必須獲取一個信號量;一旦該關鍵代碼段完成了,那麼該線程必須釋放信號量。其它想進入該關鍵代碼段的線程必須等待直到第一個線程釋放信號量。為了完成這個過程,需要創建一個信號量VI,然後將Acquire Semaphore VI以及Release Semaphore VI分別放置在每個關鍵代碼段的首末端。確認這些信號量VI引用的是初始創建的信號量。

描述
編輯
以一個停車場的運作為例。簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許其中三輛直接進入,然後放下車攔,剩下的車則必須在入口等待,此後來的車也都不得不在入口處等待。這時,有一輛車離開停車場,看門人得知後,打開車攔,放入外面的一輛進去,如果又離開兩輛,則又可以放入兩輛,如此往復。
在這個停車場系統中,車位是公共資源,每輛車好比一個線程,看門人起的就是信號量的作用。

分類
編輯
整型信號量(integer semaphore):信號量是整數
記錄型信號量(record semaphore):每個信號量s除一個整數值s.value(計數)外,還有一個進程等待隊列s.L,其中是阻塞在該信號量的各個進程的標識
二進制信號量(binary semaphore):只允許信號量取0或1值
每個信號量至少須記錄兩個信息:信號量的值和等待該信號量的進程隊列。它的類型定義如下:(用類PASCAL語言表述)
semaphore = record
value: integer;
queue: ^PCB;
end;
其中PCB是進程式控制制塊,是操作系統為每個進程建立的數據結構。
s.value>=0時,s.queue為空;
s.value<0時,s.value的絕對值為s.queue中等待進程的個數;

特性
編輯
抽象的來講,信號量的特性如下:信號量是一個非負整數(車位數),所有通過它的線程/進程(車輛)都會將該整數減一(通過它當然是為了使用資源),當該整數值為零時,所有試圖通過它的線程都將處於等待狀態。在信號量上我們定義兩種操作: Wait(等待) 和 Release(釋放)。當一個線程調用Wait操作時,它要麼得到資源然後將信號量減一,要麼一直等下去(指放入阻塞隊列),直到信號量大於等於一時。Release(釋放)實際上是在信號量上執行加操作,對應於車輛離開停車場,該操作之所以叫做「釋放」是因為釋放了由信號量守護的資源。

操作方式
編輯
對信號量有4種操作(include<semaphore>):
1. 初始化(initialize),也叫做建立(create) int sem_init(sem_t *sem, int pshared, unsigned int value);
2. 等信號(wait),也可叫做掛起(suspend)int sem_wait(sem_t *sem);
3. 給信號(signal)或發信號(post) int sem_post(sem_t *sem);
4.清理(destroy) int sem_destory(sem_t *sem);[1]

創建
編輯
同共享內存一樣,系統中同樣需要為信號量集定製一系列專有的操作函數(semget,semctl等)。系統命令ipcs可查看當前的系統IPC的狀態,在命令後使用-s參數。使用函數semget可以創建或者獲得一個信號量集ID,函數原型如下:
#include <sys/shm.h>
int semget( key_t key, int nsems, int flag);
函數中參數key用來變換成一個標識符,每一個IPC對象與一個key相對應。當新建一個共享內存段時,使用參數flag的相應許可權位對ipc_perm結構中的mode域賦值,對相應信號量集的shmid_ds初始化的值如表1所示。
shmid_ds結構初始化值表

ipc_perm結構數據

初 值

ipc_perm結構數據

初 值

Sem_otime

0

Sem_nsems

Nsems

Sem_ctime

系統當前值
   

參數nsems是一個大於等於0的值,用於指明該信號量集中可用資源數(在創建一個信號量時)。當打開一個已存在的信號量集時該參數值為0。函數執行成功,則返回信號量集的標識符(一個大於等於0的整數),失敗,則返回–1。函數semop用以操作一個信號量集,函數原型如下:
#include <sys/sem.h>
int semop( int semid, struct sembuf semoparray[], size_t nops );
函數中參數semid是一個通過semget函數返回的一個信號量標識符,參數nops標明了參數semoparray所指向數組中的元素個數。參數semoparray是一個struct sembuf結構類型的數組指針,結構sembuf來說明所要執行的操作,其定義如下:
struct sembuf{
unsigned short sem_num;
short sem_op;
short sem_flg;
}
在sembuf結構中,sem_num是相對應的信號量集中的某一個資源,所以其值是一個從0到相應的信號量集的資源總數(ipc_perm.sem_nsems)之間的整數。sem_op指明所要執行的操作,sem_flg說明函數semop的行為。sem_op的值是一個整數,如表2所示,列出了詳細sem_op的值及所對應的操作。
sem_op值詳解

Sem_op

操 作

正數

釋放相應的資源數,將sem_op的值加到信號量的值上

0

進程阻塞直到信號量的相應值為0,當信號量已經為0,函數立即返回。如果信號量的值不為0,則依據sem_flg的IPC_NOWAIT位決定函數動作。sem_flg指定IPC_NOWAIT,則semop函數出錯返回EAGAIN。sem_flg沒有指定IPC_NOWAIT,則將該信號量的semncnt值加1,然後進程掛起直到下述情況發生。信號量值為0,將信號量的semzcnt的值減1,函數semop成功返回;此信號量被刪除(只有超級用戶或創建用戶進程擁有此許可權),函數smeop出錯返回EIDRM;進程捕捉到信號,並從信號處理函數返回,在此情況將此信號量的semncnt值減1,函數semop出錯返回EINTR

負數

請求sem_op的絕對值的資源。如果相應的資源數可以滿足請求,則將該信號量的值減去sem_op的絕對值,函數成功返回。當相應的資源數不能滿足請求時,這個操作與sem_flg有關。sem_flg指定IPC_NOWAIT,則semop函數出錯返回EAGAIN。sem_flg沒有指定IPC_NOWAIT,則將該信號量的semncnt值加1,然後進程掛起直到下述情況發生:當相應的資源數可以滿足請求,該信號的值減去sem_op的絕對值。成功返回;此信號量被刪除(只有超級用戶或創建用戶進程擁有此許可權),函數smeop出錯返回EIDRM:進程捕捉到信號,並從信號處理函數返回,在此情況將此信號量的semncnt值減1,函數semop出錯返回EINTR

基本流程
編輯
下面實例演示了關於信號量操作的基本流程。程序中使用semget函數創建一個信號量集,並使用semop函數在這個信號集上執行了一次資源釋放操作。並在shell中使用命令查看系統IPC的狀態。
(1)在vi編輯器中編輯該程序。
程序清單14-10 create_sem.c 使用semget函數創建一個信號量
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
int sem_id;
int nsems = 1;
int flags = 0666;
struct sembuf buf;
sem_id = semget(IPC_PRIVATE, nsems, flags); /*創建一個新的信號量集*/
if ( sem_id < 0 ){
perror( "semget ") ;
exit (1 );
}
/*輸出相應的信號量集標識符*/
printf ( "successfully created a semaphore : %d\n", sem_id );
buf.sem_num = 0; /*定義一個信號量操作*/
buf.sem_op = 1; /*執行釋放資源操作*/
buf.sem_flg = IPC_NOWAIT; /*定義semop函數的行為*/
if ( (semop( sem_id, &buf, nsems) ) < 0) { /*執行操作*/
perror ( "semop");
exit (1 );
}
system ( "ipcs -s " ); /*查看系統IPC狀態*/
exit ( 0 );
}
(2)在vmware中編譯該程序如下:
gcc -o a.o testc_semaphore.c
(3)在shell中運行該程序如下:
./a3.o
successfully created a semaphore : 0
------ Semaphore Arrays --------
key semid owner perms nsems
0x00000000 0 zcr 666 1
在上面程序中,用semget函數創建了一個信號量集,定義信號量集的資源數為1,接下來使用semop函數進行資源釋放操作。在程序的最後使用shell命令ipcs來查看系統IPC的狀態。
%注意:命令ipcs參數-s標識查看系統IPC的信號量集狀態。

希望能幫到你,滿意望採納哦。

3、如果信號量的當前值為-4,則表示系統中在該信號量上有 ? 個等待進程?謝謝

表示有4個等待進程。

信號量的當前值如果是正值N,該值表示有N個可用資源。

如果為0,則表示所有資源全部被分配,同時沒有進程處於等待狀態

如果為負數N,則表示全部資源分配完畢,且還有N個進程處於等待該資源的狀態。

例如:若信號S的初值為3,當前值為-2,則表示有( 2 )個等待進程,當信號量的值小於0時,其絕對值表示系統中因請求該類資源而被阻塞的進程個數。

(3)函數semgetvalue擴展資料:

參數nsems是一個大於等於0的值,用於指明該信號量集中可用資源數(在創建一個信號量時)。當打開一個已存在的信號量集時該參數值為0。函數執行成功,則返回信號量集的標識符(一個大於等於0的整數),失敗,則返回–1。函數semop用以操作一個信號量集,函數原型如下:

#include <sys/sem.h>

int semop( int semid, struct sembuf semoparray[], size_t nops );

函數中參數semid是一個通過semget函數返回的一個信號量標識符,參數nops標明了參數semoparray所指向數組中的元素個數。

4、unix創建信號燈函數semget怎麼用

是的,具體可詳細參考APUE(UNIX環境高級編程)的P405,有一個popen()函數的具體實現。APUE電子書可以在網上下載。

5、linux 信號量操作函數

semget()
可以使用系統調用semget()創建一個新的信號量集,或者存取一個已經存在的信號量集:
系統調用:semget();
原型:intsemget(key_t key,int nsems,int semflg);
返回值:如果成功,則返回信號量集的IPC標識符。如果失敗,則返回-1:errno=EACCESS(沒有許可權)
EEXIST(信號量集已經存在,無法創建)
EIDRM(信號量集已經刪除)
ENOENT(信號量集不存在,同時沒有使用IPC_CREAT)
ENOMEM(沒有足夠的內存創建新的信號量集)
ENOSPC(超出限制)
系統調用semget()的第一個參數是關鍵字值(一般是由系統調用ftok()返回的)。系統內核將此值和系統中存在的其他的信號量集的關鍵字值進行比 較。打開和存取操作與參數semflg中的內容相關。IPC_CREAT如果信號量集在系統內核中不存在,則創建信號量集。IPC_EXCL當和 IPC_CREAT一同使用時,如果信號量集已經存在,則調用失敗。如果單獨使用IPC_CREAT,則semget()要麼返回新創建的信號量集的標識 符,要麼返回系統中已經存在的同樣的關鍵字值的信號量的標識符。如果IPC_EXCL和IPC_CREAT一同使用,則要麼返回新創建的信號量集的標識 符,要麼返回-1。IPC_EXCL單獨使用沒有意義。參數nsems指出了一個新的信號量集中應該創建的信號量的個數。信號量集中最多的信號量的個數是 在linux/sem.h中定義的:
#defineSEMMSL32/*<=512maxnumofsemaphoresperid*/
下面是一個打開和創建信號量集的程序:
intopen_semaphore_set(key_t keyval,int numsems)
{
intsid;
if(!numsems)
return(-1);
if((sid=semget(mykey,numsems,IPC_CREAT|0660))==-1)
{
return(-1);
}
return(sid);
}
};
==============================================================
semop()
系統調用:semop();
調用原型:int semop(int semid,struct sembuf*sops,unsign ednsops);
返回值:0,如果成功。-1,如果失敗:errno=E2BIG(nsops大於最大的ops數目)
EACCESS(許可權不夠)
EAGAIN(使用了IPC_NOWAIT,但操作不能繼續進行)
EFAULT(sops指向的地址無效)
EIDRM(信號量集已經刪除)
EINTR(當睡眠時接收到其他信號)
EINVAL(信號量集不存在,或者semid無效)
ENOMEM(使用了SEM_UNDO,但無足夠的內存創建所需的數據結構)
ERANGE(信號量值超出范圍)
第一個參數是關鍵字值。第二個參數是指向將要操作的數組的指針。第三個參數是數組中的操作的個數。參數sops指向由sembuf組成的數組。此數組是在linux/sem.h中定義的:
/*semop systemcall takes an array of these*/
structsembuf{
ushortsem_num;/*semaphore index in array*/
shortsem_op;/*semaphore operation*/
shortsem_flg;/*operation flags*/
sem_num將要處理的信號量的個數。
sem_op要執行的操作。
sem_flg操作標志。
如果sem_op是負數,那麼信號量將減去它的值。這和信號量控制的資源有關。如果沒有使用IPC_NOWAIT,那麼調用進程將進入睡眠狀態,直到信號 量控制的資源可以使用為止。如果sem_op是正數,則信號量加上它的值。這也就是進程釋放信號量控制的資源。最後,如果sem_op是0,那麼調用進程 將調用sleep(),直到信號量的值為0。這在一個進程等待完全空閑的資源時使用。

6、Linux中semget函數的參數key和函數返回值的作用區別是什麼?

key是給內核看的,不同進程用同一個key可以返回一個相同的ID
而返回值是給內核管理用的
二者一一對應,key給應用自由,返回的ID是為了內核管理方便

7、使用信號量實現有限緩沖區的生產者和消費者問題(使用fork(),semget()等函數,能在GCC下運行)

看我下面的代碼, 父進程是消費者,子進程是生產者。

REPEATS 決定總共生產的次數 (可以自己修改)
CONSUMER_SPEED 決定消費的速度 (越大越慢,可以自己修改)
PRODUCER_SPEED 決定生產的速度 (越大越慢,可以自己修改)

我的例子里,生產者生產一個隨機數。另外消費速度比生產速度慢,所以可以看到輸出中,+++ (生產者) 開頭的出現的比--- (消費者)多,當生產者結束後,就只有 --- 列印了。

對這個程序由什麼問題,可以baidu hi我。在linux/unix下用 gcc 編譯。

#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>

#define REPEATS (10) /* count of proction/consumption */

#define MAX_BUFFER_SIZE (8)

typedef struct
{
int bottom;
int top;

int data[MAX_BUFFER_SIZE];
} STRUCT_BUFFER;

STRUCT_BUFFER * pBuffer = NULL;

/* Define speed of consumer/procer, change them as u like */
#define PRODUCER_SPEED (1) /* 1/sec */
#define CONSUMER_SPEED (2) /* 1/2sec */

int sem_consume; /* consumer sem */
int sem_proce; /* procer sem */
int shm_buffer; /* shared buffer */

#define FLAG (IPC_CREAT | S_IRWXU)

/* Init semphores & shared buffer */
void init()
{
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
} arg;

shm_buffer = shmget(0x1111, sizeof(STRUCT_BUFFER), FLAG);
pBuffer = shmat(shm_buffer, 0, 0);
memset(pBuffer, 0, sizeof(STRUCT_BUFFER));

sem_consume = semget(0x2222, 1, FLAG);
arg.val = 0;
if (semctl(sem_consume, 0, SETVAL, arg) < 0)
{
perror("Consumer");
exit(1);
}

sem_proce = semget(0x3333, 1, FLAG);
arg.val = MAX_BUFFER_SIZE;
if (semctl(sem_proce, 0, SETVAL, arg) < 0)
{
perror("Procer");
exit(1);
}
}

/* destroy semphores & shared buffer */
void deinit()
{
shmctl(shm_buffer, IPC_RMID, NULL);
semctl(sem_consume, 0, IPC_RMID);
semctl(sem_proce, 0, IPC_RMID);
}

int main()
{
int pid, i;
struct sembuf sbuf;

init();

printf("Start fork...\n");
pid = fork();

if (pid > 0)
{
/* parent process, consumer */
for (i = 0; i < REPEATS; i++)
{
/* Try decrementing 1 from consumer */
sbuf.sem_num=0;
sbuf.sem_op=-1;
sbuf.sem_flg=0;
semop(sem_consume, &sbuf, 1);

/* OK */
printf("Consumer get %6d\n", pBuffer->data[pBuffer->bottom]);
pBuffer->bottom = (pBuffer->bottom+1)%MAX_BUFFER_SIZE;

/* Try incrementing 1 to procer */
sbuf.sem_op = 1;
semop(sem_proce, &sbuf, 1);

sleep(CONSUMER_SPEED);
}
wait(0);
shmdt(pBuffer);
}
else if (pid == 0)
{
srand(time(NULL));
/* child process, procer */
for (i = 0; i < REPEATS; i++)
{
/* Try decrementing 1 from procer */
sbuf.sem_num=0;
sbuf.sem_op=-1;
sbuf.sem_flg=0;
semop(sem_proce, &sbuf, 1);

/* OK */
pBuffer->data[pBuffer->top] = (rand()%1000)*1000 + i + 1;
printf("Procer put %6d\n", pBuffer->data[pBuffer->top]);
pBuffer->top = (pBuffer->top+1)%MAX_BUFFER_SIZE;

/* Try incrementing 1 to consumer */
sbuf.sem_op = 1;
semop(sem_consume, &sbuf, 1);

sleep(PRODUCER_SPEED);
}
shmdt(pBuffer);
exit(0);
}

deinit();
return 0;
}

與函數semgetvalue相關的知識