여러 생산자와 여러 소비자문제...

jinguman의 이미지

혹시 위키백과에 나온..
--------------------------
* 생산자 프로세스
do {
...
아이템을 생산한다.
...
wait(empty); //버퍼에 빈 공간이 생길 때까지 기다린다.
wait(mutex); //임계 구역에 진입할 수 있을 때까지 기다린다.
...
아이템을 버퍼에 추가한다.
...
signal(mutex); //임계 구역을 빠져나왔다고 알려준다.
signal(full); //버퍼에 아이템이 있다고 알려준다.
} while (1);
* 소비자 프로세스
do {
wait(full); //버퍼에 아이템이 생길 때까지 기다린다.
wait(mutex);
...
버퍼로부터 아이템을 가져온다.
...
signal(mutex);
signal(empty); //버퍼에 빈 공간이 생겼다고 알려준다.
...
아이템을 소비한다.
...
} while (1);
-------------------------
위 알고리즘 써보신분 계신가요.. 그대로 프로그램을 짜서 테스트를 해 보면, 어느순간부터
세마포어 연산에러(정확히는 P연산에러)가 뜨는데, 도대체 이유를 모르겠네요;;;
사용 소스를 같이 올리니 검토 부탁드립니다.
------------------------

 
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
 
#define MAX_Q_SIZE 10
#define MAX_PRODUCT_SIZE 1  							// product process number
#define MAX_CUSTOMER_SIZE 1								// customer process number 
#define MAX_PROCESS (MAX_PRODUCT_SIZE+MAX_CUSTOMER_SIZE)// total process number
 
/* init variable */
int sem_id;				// for mutex, mutex = 1
int full_sem_id;		// for empty semaphore, full = 0
int empty_sem_id;		// for empty semaphore, empty = n
int temp = 0;
 
 
/* job process ft */
void tfunc_a();				// product process
void tfunc_b();				// customer process
 
/* sem ft */
int sysv_semget(char *tok, key_t sem_fixkey, int n_sem, int sem_value, int user_mode);
int sysv_semrm(int sem_id);
int sysv_semwait(int sem_id, int sem_idx);
int sysv_sempost(int sem_id, int sem_idx);
int sysv_semval(int sem_id, int sem_idx);
 
/* define of semaphore union struct */
union semun {
	int val;                    
	struct semid_ds *buf;       
	unsigned short int *array;  
	struct seminfo *__buf;      
};
 
/* Name : main
 * Desc : Main function
 * Argv : int argc, char *argv
 * Ret  : void
 */
int main(int argc,char *argv[])
{
	int i,status;
 
	/* sem id getting */
	sem_id = sysv_semget(NULL, 0x12340001, 1, 1, 0660);
	empty_sem_id = sysv_semget(NULL, 0x12340002, 1, MAX_Q_SIZE, 0660);
	full_sem_id = sysv_semget(NULL, 0x12340003, 1, 0, 0660);
 
	/* fork */
	for (i=0;i<MAX_PROCESS;i++) {
		switch(fork()) {
			case 0: /* child */
 
				/* decide of process content */
				if ( i >= 0 && i < MAX_CUSTOMER_SIZE ) {
					tfunc_b();
				} else {
					tfunc_a();
 
				}
 
				exit(0);
			case -1:
				perror("fork() error\n");
				exit(-1);
			default:
				break;
		}				
	}
 
	/* wait for child process */
	for (i=0;i<MAX_PROCESS;i++) {
		waitpid(-1,&status,0);
	}
 
	/* sem remove */
	if (sysv_semrm(sem_id) == -1) {
		perror("FAIL: sysv_semrm"); return EXIT_FAILURE;
	}
 
	if (sysv_semrm(full_sem_id) == -1) {
		perror("FAIL: sysv_semrm"); return EXIT_FAILURE;
	}
 
	if (sysv_semrm(empty_sem_id) == -1) {
		perror("FAIL: sysv_semrm"); return EXIT_FAILURE;
	}
 
 
	return 0;	
}
 
/* Name : tfunc_a
 * Desc : action of item product (getting or creation)
 * Argv : void
 * Ret  : void
 */
void tfunc_a()
{
	while(1)
	{
			sysv_semwait(empty_sem_id, 0);		
			sysv_semwait(sem_id, 0);
 
			temp++;
			printf("TFUNC_A] insert %d\n",temp);
 
			sysv_sempost(sem_id, 0);
			sysv_sempost(full_sem_id, 0);		
 
 
 
	}
 
	return;
}
 
/* Name : tfunc_b
 * Desc : action of item consume
 * Argv : void
 * Ret  : void
 */
void tfunc_b()
{
	while(1)
	{
			sysv_semwait(full_sem_id, 0);		
			sysv_semwait(sem_id, 0);
 
			temp++;
			printf("\t\tTFUNC_B] pop %d\n",temp);
 
			sysv_sempost(sem_id, 0);
			sysv_sempost(empty_sem_id, 0);						
	}
 
	return;
}
 
 
/* Name : sysv_shmget
 * Desc : init shared memory (getting or creation)
 * Argv : long key_shm, int n_size (byte), mode(octal notation)
 * Ret  : shm ID (if success), -1 (if fail)
 */
int sysv_shmget(char *tok, key_t shm_fixkey, int size, int user_mode)
{
	key_t	shm_key;
	int	shm_id;
 
	if (tok != NULL) {
		if ((shm_key = ftok(tok, 1234)) == -1) {
			return -1;
		}
	} else {
		shm_key = shm_fixkey;
	}
 
	if ((shm_id = shmget(shm_key, size, IPC_CREAT|user_mode)) == -1) {
		if (errno == EEXIST) { /* already exist shm, just get ipc id */
			shm_id = shmget(shm_key, 0, 0);
		}
	}
	if (shm_id == -1)
		fprintf(stderr,"FAIL: shmget():%s [%s:%d]\n", strerror(errno), __FUNCTION__, __LINE__);
	return shm_id;
}
 
int sysv_shmrm(int shm_id)
{
	int		ret;
	if ((ret = shmctl(shm_id, IPC_RMID, NULL)) == -1) {
		fprintf(stderr,"FAIL: shmctl():%s [%s:%d]\n", 
			strerror(errno), __FUNCTION__, __LINE__);
		return -1;
	}
	return ret;
}
 
/* Name : sysv_semget
 * Desc : init semaphore (getting or creation)
 * Argv : long key_sem, int n_sem, user_mode(octal notation)
 * Ret  : semaphore ID (if success), -1 (if fail)
 */
int sysv_semget(char *tok, key_t sem_fixkey, int n_sem, int sem_value, int user_mode)
{
	int	sem_id, i;
	union semun semun;
	unsigned short int *arr_semval = NULL;
	key_t	sem_key;
 
	/* if tok is not NULL, we make IPC key for semaphore */
	if (tok != NULL) {
		if ((sem_key = ftok(tok, 1234)) == -1) {
			return -1;
		}
	} else {
		sem_key = sem_fixkey;
	}
	if ((sem_id = semget(sem_key, n_sem, IPC_CREAT|IPC_EXCL|user_mode)) == -1) {
		if (errno == EEXIST) {
			/* Is exist ? */
			sem_id = semget(sem_key, n_sem, 0);
			return sem_id;
		}
	}
	if (sem_id == -1) {
		fprintf(stderr,"FAIL: semget [%s:%d]\n", __FUNCTION__, __LINE__);
		return -1;
	}
 
	/* init semaphore value */
	if ((arr_semval = (unsigned short int *)malloc(sizeof(unsigned short int) * n_sem)) == NULL) {
		fprintf(stderr, "FAIL: malloc [%s:%d]\n", __FUNCTION__, __LINE__);
		return -1;
	}
 
	for(i=0; i<n_sem; i++) arr_semval[i] = sem_value;
	semun.array = arr_semval;
	if (semctl(sem_id, 0, SETALL, semun) == -1) {
		fprintf(stderr, "FAIL: semctl [%s:%d]\n", __FUNCTION__, __LINE__);
		if (arr_semval != NULL) free(arr_semval);
		return -1;
	}
	if (arr_semval != NULL) free(arr_semval);
	return sem_id;
}
 
/* Name : sysv_semrm
 * Desc : remove specified semaphore with sem_id
 * Argv : int sem_id
 * Ret  : 0 (if success), -1 (if fail)
 */
int sysv_semrm(int sem_id)
{
	if (semctl(sem_id, 0, IPC_RMID) == -1) {
		fprintf(stderr, "FAIL: semctl() 'IPC_RMID' [%s:%d]\n", __FUNCTION__, __LINE__);
		return -1;
	}
	return 0;
}
 
/* Name : sysv_semwait
 * Desc : P operation about specified SysV semaphore
 * Argv : int sem_id, int sem_idx
 * Ret  : 0 (if success), -1 (if fail)
 */
int sysv_semwait(int _sem_id, int sem_idx)
{
	struct sembuf	sem_buf;
 
	sem_buf.sem_num = sem_idx;
	sem_buf.sem_flg = SEM_UNDO;
	sem_buf.sem_op = -1;
	if (semop(_sem_id, &sem_buf, 1) == -1) {
		fprintf(stderr, "FAIL: semop() 'P' operation [%s:%d]\n", __FUNCTION__, __LINE__);
		getchar();
		return -1;
	}
	return 0;
}
 
/* Name : sysv_sempost
 * Desc : V operation about specified SysV semaphore
 * Argv : int sem_id, int sem_idx
 * Ret  : 0 (if success), -1 (if fail)
 */
int sysv_sempost(int _sem_id, int sem_idx)
{
	struct sembuf	sem_buf;
	sem_buf.sem_num = sem_idx;
	sem_buf.sem_flg = SEM_UNDO;
	sem_buf.sem_op = 1;
	if (semop(_sem_id, &sem_buf, 1) == -1) {
		fprintf(stderr, "FAIL: semop() 'P' operation [%s:%d]\n", __FUNCTION__, __LINE__);
		getchar();
		return -1;
	}
	return 0;
}
 
/* Name : sysv_semval
 * Desc : get specified semaphore value 
 * Argv : int sem_id, int sem_idx
 * Ret  : semaphore value (if success), -1 (if fail)
 */
int sysv_semval(int _sem_id, int sem_idx)
{
	int	semval;
	if ((semval = semctl(_sem_id, sem_idx, GETVAL)) == -1) {
		fprintf(stderr, "FAIL: semctl() 'GETVAL' [%s:%d]\n", __FUNCTION__, __LINE__);
		return -1;
	}
	return semval;
}

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.