IPC研究(4) ---- semaphores

============================================================
IPC --- System V IPC --- semaphores

Related System Calls:
[designed to work for arrays of semaphore values]
#include <sys/sem.h>
semctl
semget
semop


Basics:
Purpose: provide the feature for a single process to have exclusive access to a resource
Application scenes: multi-threaded programs, multiprocess programs or a combine of the two
General definition: two operations -- P(wait) and V(signal)

=> binaray semaphore (0,1)
=> general semaphore (0,1,2,...)

和file相似,不一樣的進程會有不一樣的semaphore identifier,可是,它們都指向同一個semaphore。(就像fd和inode)
對於file,不一樣的進程用filename來獲得file descriptors,對於semaphore,不一樣的進程用key來獲得不一樣的semaphore identifiers。

用semaphore通訊的各個進程間,須要有個共同的key。


Analysis:
1. Linux Kernel是如何支持semaphore通訊機制的呢?
struct_task結構中有相應的semaphore的域,若是systemV IPC支持被編譯進來,就能夠支持。

2. semaphore主要是用來解決資源訪問衝突的問題的。對於資源訪問的競爭問題,有以下模型:
process1 |
process2 | <==> RESOURCE
process3 |
要使訪問資源不由於出現競爭狀態而出現不想要的結果,有兩種方法。
第一,在resource側作控制,組織多個進程同時訪問,或者對將訪問block。好比file lock
第二,在訪問的process間作控制,使得他們可以互相通訊,從而解決訪問衝突。
在Linux中,第二種解決方案,就是semaphore。



Examples:


#ifndef _JAMES_C_SEMAPHORE_H
#define _JAMES_C_SEMAPHORE_H

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

union semun
{
	int val;		/* value for SETVAL */
	struct semid_ds *buf;	/* buffer for IPC_STAT, IPC_SET */
	unsigned short *array;	/* array for GETALL SETALL */
	struct seminfo __buf;	/* buffer for IPC_INFO (Linux-specific) */
};

int set_semvalue(int sem_id);
void del_semvalue(int sem_id);
int semaphore_p(int sem_id);
int semaphore_v(int sem_id);

#endif 

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "mysem.h"

int set_semvalue(int sem_id)
{
	union semun sem_union;
	sem_union.val = 1;
	if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
		return -1;
	return 0;
}

void del_semvalue(int sem_id)
{
	union semun sem_union;
	if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
		perror("Failed to delete semaphore");
}

int semaphore_p(int sem_id)
{
	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 -1;
	}
	return 0;
}

int semaphore_v(int sem_id)
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = 1;
	sem_b.sem_flg = SEM_UNDO;
	if (semop(sem_id, &sem_b, 1) == -1)
	{
		fprintf(stderr, "semaphore_v failed\n");
		return -1;
	}
	return 0;
}

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "mysem.h"

int main(int argc, char *argv[])
{
	int sem_id;
	int i;
	int pause_time;
	char op_char;

	srand( (unsigned int)getpid() );
	op_char = 'a' + rand()%26; /* other process */

	sem_id = semget( (key_t)1234, 1, 0666 | IPC_CREAT);

	if (argc > 1)
	{
		if ( set_semvalue(sem_id) < 0)
		{
			fprintf(stderr, "Failed to initialize semaphore\n");
			exit(-1);
		}
		op_char = 'X';	/* creation process */
		sleep(2);
	}
	for (i=0; i<5; i++)
	{
		if (semaphore_p(sem_id) < 0)
			exit(-1);
		printf("%c", op_char); fflush(stdout);
		pause_time = rand()%3;
		sleep(pause_time);
		printf("%c", op_char); fflush(stdout);
		if (semaphore_v(sem_id) < 0)
			exit(-1);
		sleep(pause_time);
	}
	printf("\n%d - finished\n", getpid());

	if (argc > 1)
	{
		sleep(10);
		del_semvalue(sem_id);
	}
	return 0;
}
相關文章
相關標籤/搜索