Linux 신 호 량 생산자 소비자 사례

28406 단어 생산자 소비자
채소 새 는 우연히 신 호 량 을 만 나 불꽃 을 낸다.그래서 인터넷 에서 자 료 를 검색 하고 을 보면 서 몇 가지 예 제 를 실 현 했 습 니 다. 고 수 는 뿌리 지 마 세 요!이 몇 분 은 아주 잘 쓰 셨 군요.
제목: http://www.it165.net/os/html/201312/7039.html
신 호 량 및 그 용법: http://www.cnblogs.com/hjslovewcl/archive/2011/03/03/2314341.html
Mutex 와 Semaphore 의 구별 이 유명한 화장실 이론: http://koti.mbnet.fi/niclasw/MutexSemaphore.html
 아이고, 들 켰 다!나 는 고의로 다른 사람 을 훔 쳐 본 것 이 아니다.
 
1. 생산자, 소비자, 자원 현황
이러한 상황 은 하나의 신 호 량 만 사용 할 수 있 습 니 다. 생 성 하거나 소비 하려 면 이 신 호 량 만 얻 으 려 고 합 니 다. 여 기 는 full = 1 과 empty = 0 을 사 용 했 습 니 다. 두 개 는 뒤쪽 과 일치 하기 위해 서 입 니 다. 1, 0 은 초기 값 입 니 다.생산자 와 소비자 의 상황 은 다음 과 같다.
//
P(empty)
              
V(full)


//
P(full)
        
V(empty)

생산자 가 가장 먼저 자원 을 생산 하기 시작 하면 P (empty), full 과 empty 는 모두 0 이 된다. 이때 소비자 가 소비 하고 싶 으 면 P (full) 일 때 full 이 0 이면 잠 을 자고 기다린다. 생산자 가 태 어 나 면 full 을 1 로 더 하고 소비자 가 불쌍 하 게 잠 든 것 을 보면 깨 우 고 소비 자 는 full 을 1 로 줄 여 스스로 즐겁게 한다.
소비자 소비 과정 에서 생산자 가 낳 으 려 면 empty 가 0 이 라 휴면 하고 소비자 가 끝나 면 empty 를 1 로 더 한 후 생산자 가 생산 을 시작한다.
위의 것 은 이해 하기 쉽 고 아래 의 코드 는:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#include <x86_64-linux-gnu/sys/types.h>
#include <x86_64-linux-gnu/sys/ipc.h>
#include <x86_64-linux-gnu/sys/sem.h>

int semInite(int semId, int value);
int semDelete(int semId);
int semP(int semId);
int semV(int semId);

//declare a union to be used
union semun 
{
    int val;                        /* value for SETVAL */ 
    struct semid_ds *buf;                /* buffer for IPC_STAT, IPC_SET */ 
    unsigned short int *array;         /* array for GETALL, SETALL */ 
    struct seminfo *__buf;                /* buffer for IPC_INFO */ 
};


//semaphore declare
static int semFullId;
static int semEmptyId;
static int source = 0;        //source definition    


//new thread as a consumer
void* child_thread(void* arg)
{
    int ttt = 1;
        
    while(1)
    {
        sleep(rand() % 19);
        printf("child No.%d times wants to consume...
", ttt); semP(semFullId); // printf("child No.%d times start consuming. source = %d
", ttt, source); source = 0; printf("child No.%d times end consuming. source = %d

", ttt++, source); semV(semEmptyId); // } return (void*)0; } int main(void) { //create semaphore semFullId = semget((key_t)1235, 1, 0666 | IPC_CREAT); semEmptyId = semget((key_t)1236, 1, 0666 | IPC_CREAT); semInite(semFullId, 0); semInite(semEmptyId, 1); pthread_t pid; pthread_create(&pid, NULL, child_thread, NULL); int tt = 1; while(1) { sleep(rand() % 18); printf("parent No.%d times wants to produce...
", tt); semP(semEmptyId); // printf("parent No.%d times start producing. source = %d
", tt, source); source = rand() % 100; printf("parent No.%d times end producing. source = %d
", tt++, source); semV(semFullId); // } semDelete(semFullId); semDelete(semEmptyId); return 0; } //set semaphore as default value int semInite(int semId, int value) { union semun semUnion; semUnion.val = value; //set default semaphore return semctl(semId, 0, SETVAL, semUnion); } //delete semaphore int semDelete(int semId) { union semun semUnion; return semctl(semId, 0, IPC_RMID, semUnion); } //semaphore P operation int semP(int semId) { struct sembuf semBuf; semBuf.sem_num = 0; //indicate it is not semaphore array semBuf.sem_op = -1; //subtract one semBuf.sem_flg = SEM_UNDO; return semop(semId, &semBuf, 1); //return value } //semaphore V operation int semV(int semId) { struct sembuf semBuf; semBuf.sem_num = 0; //indicate it is not semaphore array semBuf.sem_op = 1; //subtract one semBuf.sem_flg = SEM_UNDO; return semop(semId, &semBuf, 1); //return value }

111
두 신 호 량 은 사실 신 호 량 으로 집합 해 야 한다. 왜냐하면 그것 은 원래 집합 을 겨냥 한 것 이기 때문이다. 그러나 막 입문 하기 때문에 이해 하기 위해 두 개 를 사용한다.두 스 레 드, 새로 만 든 스 레 드 를 소비자 로 삼 았 습 니 다.그 중에서 유 닉 스 의 몇 가지 신 호 량 의 함 수 를 반나절 동안 보 았 는데 좀 복잡 합 니 다. 쉽게 말 하면 정확 하지 않 습 니 다.
//        ,                ,
//  unix         ,  1         
//        
int semget(key_t key, int num_sems, int sem_flags);

//        ,        P、V  +1 -1    
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);

//
int semctl(int sem_id, int sem_num, int command, ...);

실행:
Linux 信号量 生产者消费者小例题_第1张图片
 
2. 한 생산자, 한 소비자, N 개 자원 현황
이곳 의 자원 은 하나의 배열 로 대체 되 었 다.사실은 본질 적 으로 위 와 비슷 하 다. 매번 생산자 나 소비자 중 한 명 만 들 어가 게 하고 들 어가 서 어느 곳 에 놓 거나 어느 곳 에서 찾 으 면 하나의 표지 로 설명 해 야 한다. 사실은 모든 자원 에 신 호 량 을 더 할 수 있다.
여기 서 생산자 와 소비자 에 게 static 변 수 를 커서 로 설정 하여 다음 자원 을 어느 위치 에 두 고 다음 에 어디서 자원 을 찾 는 지 알려 줍 니 다.staitic 변 수 는 한 번 만 초기 화 되 기 때문에 여기에 사용 하기에 적합 합 니 다.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

#include <x86_64-linux-gnu/sys/types.h>
#include <x86_64-linux-gnu/sys/ipc.h>
#include <x86_64-linux-gnu/sys/sem.h>

#define N 5

int semInite(int semId, int value);
int semDelete(int semId);
int semP(int semId);
int semV(int semId);

//declare a union to be used
union semun 
{
    int val;                        /* value for SETVAL */ 
    struct semid_ds *buf;                /* buffer for IPC_STAT, IPC_SET */ 
    unsigned short int *array;         /* array for GETALL, SETALL */ 
    struct seminfo *__buf;                /* buffer for IPC_INFO */ 
};


//semaphore declare
static int semFullId;
static int semEmptyId;
static int srcArr[N];        //source definition    


//new thread as a consumer
void* child_thread(void* arg)
{
    int ttt = 1;
        
    while(1)
    {
        static int pToGet = 0;    //get source from the position
        sleep(rand() % 19);
        printf("child No.%d times wants to consume(get from index %d)...
", ttt, pToGet); semP(semFullId); // printf("child No.%d times start consuming.(get from index %d, data is %d)
", ttt, pToGet, srcArr[pToGet]); srcArr[pToGet] = 0; printf("child No.%d times end consuming. (get from index %d)

", ttt++, pToGet); pToGet = (pToGet + 1) % N; semV(semEmptyId); // } return (void*)0; } int main(void) { //create semaphore semFullId = semget((key_t)1235, 1, 0666 | IPC_CREAT); semEmptyId = semget((key_t)1236, 1, 0666 | IPC_CREAT); semInite(semFullId, 0); semInite(semEmptyId, N); //N source pthread_t pid; pthread_create(&pid, NULL, child_thread, NULL); int tt = 1; while(1) { static int pToPut = 0; //next position where source to be filled in sleep(rand() % 18); printf("parent No.%d times wants to produce(put in %d index)...
", tt, pToPut); semP(semEmptyId); // printf("parent No.%d times start producing.(put in %d index, original data is %d)
", tt, pToPut, srcArr[pToPut]); int temp = rand() % 100; srcArr[pToPut] = temp; printf("parent No.%d times end producing.(put in %d index, now data is %d)
", tt++, pToPut, srcArr[pToPut]); pToPut = (pToPut + 1) % N; semV(semFullId); // } semDelete(semFullId); semDelete(semEmptyId); return 0; } //set semaphore as default value int semInite(int semId, int value) { union semun semUnion; semUnion.val = value; //set default semaphore return semctl(semId, 0, SETVAL, semUnion); } //delete semaphore int semDelete(int semId) { union semun semUnion; return semctl(semId, 0, IPC_RMID, semUnion); } //semaphore P operation int semP(int semId) { struct sembuf semBuf; semBuf.sem_num = 0; //indicate it is not semaphore array semBuf.sem_op = -1; //subtract one semBuf.sem_flg = SEM_UNDO; return semop(semId, &semBuf, 1); //return value } //semaphore V operation int semV(int semId) { struct sembuf semBuf; semBuf.sem_num = 0; //indicate it is not semaphore array semBuf.sem_op = 1; //subtract one semBuf.sem_flg = SEM_UNDO; return semop(semId, &semBuf, 1); //return value }

222
실행 결과:
Linux 信号量 生产者消费者小例题_第2张图片
 
3. N 개 생산자, N 개 소비자, N 개 자원
 이런 상황 은 생산자 와 소비자 간 에 상술 한 방식 을 통 해 자원 사용 을 조율 해 야 할 뿐만 아니 라 생산자 내부 와 소비자 내부 도 조율 해 야 한다.네 개의 신 호 량 정의:
empty - 버퍼 가 비어 있 는 지, 초기 값 은 n 입 니 다.full - 버퍼 가 가득 찼 는 지, 초기 값 이 0 인지 표시 합 니 다.mutex 1 - 생산자 간 의 상호 배척 신 호 량, 초기 값 은 1 이다.mutex 2 - 소비자 간 의 상호 배척 신 호 량, 초기 값 은 1 이다.
//     
P(mutex1)
    P(empty)
                   
    V(full)
V(mutex1)

//     
P(mutex2)
    P(full)
            
    V(empty)
V(mutex2)

사실 위의 생산자 나 소비자 가 상호 배척 량 이나 신 호 량 을 얻 는 순 서 는 뒤 바 뀔 수 있 고 자물쇠 가 생기 지 않 는 다.
물론 이 문 제 는 다른 더 좋 은 방법 으로 해결 할 수 있 고 나 는 계속 공부 해 야 한다.

좋은 웹페이지 즐겨찾기