1. 程式人生 > >程序間的通訊方式_訊號量

程序間的通訊方式_訊號量

訊號量

       當我們編寫的程式使用了執行緒時,不管它是執行在多使用者系統上、多執行緒系統上,還是執行在多使用者多程序系統上,我們通常會發現程式中存在著一部分臨界程式碼,我們需要只有一個程序(或一個執行執行緒)可以進入這個臨界程式碼並擁有對資源獨佔式的訪問權。為了防止出現因多個程式同時訪問一個共享資源而引發的問題,我們需要有一種方法,它可以通過生成並使用令牌來授權,在任一時刻只能有一個執行執行緒訪問程式碼的臨界區域。訊號量的一個更正式的定義式是:它是一個特殊變數,只允許對它進行等待(wait)和傳送訊號(signal)這兩種操作。

1. 臨界資源

    同一時刻只能被一個程序訪問的資源

2. 臨界區

    訪問臨界資原始碼區域

3. 原子操作

    任何情況下都不能被打斷的操作

4. 核心物件

    用於對程序間通訊時,多程序能夠訪問同一資源的記錄

訊號量的作用:程序間同步控制,訊號量相當於記錄資源能夠同時被多少個程序訪問

訊號量的操作:

       建立或獲取:如果是建立,必須初始化;如果獲取,則不能初始化。

       減一操作:P 操作

       加一操作:V 操作

       刪除:

訊號量操作的相關函式:

       int semget((key_t)key, int nsems, int flag);   //建立或者獲取

            第一個引數 key 是整數值,不相關的程序可以通過它訪問同一個訊號量。

            nsems 引數指定需要的訊號量數目,它幾乎總是取值為1。

            flag 引數是一組標誌,它與 open 的函式標誌非常相似。

       int semop(int semid, struct sembuf *buf, int lenyh);   //P  V 操作,用於改變訊號量的值

            第一個引數 semid 是有semget返回的訊號量識別符號。

            第二個引數 buf 是指向一個結構體陣列的指標,每個陣列元素至少包括以下幾個成員:

                   struct sembuf

                   {

                       short sem_num;    //訊號量編號

                       short sem_op;    //訊號量在一次操作中需要改變的值,-1為 P 操作,+1為 V 操作

                       short sem_flg;   

                   }

       int semctl(int semid, int pos, int cmd, /*union semun un*/);

            cmd 引數為將要採取的動作。

練習:A 程序輸入“OK”,B 程序輸出數字0~9。

程式碼如下:

#ifndef _SEM_H
#define _SEM_H

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

int semid;

union semun
{
	int val;
};

void sem_get();
void sem_p();
void sem_v();
void sem_del();

#endif
#include "sem.h"

void sem_get()
{
	semid = semget((key_t)1234, 1, 0664);
	if (semid == -1)
	{
		semid = semget((key_t)1234, 1, 0664 | IPC_CREAT);
		assert(semid != -1);

		union semun v;
		v.val = 0;
		if (semctl(semid, 0, SETVAL, v) == -1)
		{
			perror("error");
			exit(0);
		}
	}
}

void sem_p()
{
	struct sembuf buffer;
	buffer.sem_num = 0;
	buffer.sem_op = -1;
	buffer.sem_flg = SEM_UNDO;

	if (semop(semid, &buffer, 1) == -1)
	{
		perror("p error");
		exit(0);
	}
}

void sem_v()
{
	struct sembuf buffer;
	buffer.sem_num = 0;
	buffer.sem_op = 1;
	buffer.sem_flg = SEM_UNDO;

	if (semop(semid, &buffer, 1) == -1)
	{
		perror("v error");
		exit(0);
	}
}

void sem_del()
{
	if (semctl(semid, 0, IPC_RMID) == -1)
	{
		perror("del error");
		exit(0);
	}
}

程序 A 程式碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
//#include <sys/ipc.h>
//#include <sys/sem.h>
#include "sem.h"
#include "sem.c"

int main()
{
	sem_get();

	while (1)
	{
		printf("Please input: ");
		fflush(stdout);

		char buffer[128] = {0};
		fgets(buffer, 127, stdin);
		buffer[strlen(buffer)-1] = 0;

		if (strncmp(buffer, "OK", 2) == 0)
		{
			sem_v();
		}

		if (strncmp(buffer, "end", 3) == 0)
		{
			break;
		}
	}
	sem_del();
	return 0;
}

B 程序程式碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
//#include <sys/ipc.h>
//#include <sys/sem.h>
#include "sem.h"
#include "sem.c"

int main()
{
	sem_get();
	sem_p();
	for (int i=0; i<10; i++)
	{
		printf("%d \n", i);
	}

	sem_del();
	return 0;
}