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;
}


你可能感兴趣的:(IPC研究(4) ---- semaphores)