天天看點

作業系統實驗——信号量

生産者和消費者

#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/shm.h>
#include<sys/mman.h>
#include<stdio.h>
#include<stdlib.h>

#define SHM_SIZE (1024*1024)
#define SHM_MODE 0600
#define SEM_MODE 0600

#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)  
/*   union   semun   is   defined   by   including   <sys/sem.h>   */   
#else   
/*   according   to   X/OPEN   we   have   to   define   it   ourselves   */   
union semun{  
    int val;  
    struct semid_ds *buf;  
    unsigned short *array;  
};  
#endif  
  
struct ShM{  
    int start;  
    int end;  
}* pSM;  

int count=30;//計數器,produce執行30次後終止程式
const int num_of_consumer = 3;//消費者數量
const int size_of_buffer=5;//緩沖區大小
int shmId = -1;
int semSetId = -1;
union semun su;//sem union,用于初始化信号量


void semWait(int semSetId,int semNum)
{
    struct sembuf sb;
    sb.sem_num = semNum;
    sb.sem_op = -1;//表示信号量減1
    sb.sem_flg = SEM_UNDO;//程序結束時,相應的操作被取消

    //第 3 個參數表示數組sb的大小
    if(semop(semSetId,&sb,1)<0)
    {
        perror("semWait failed!");
        exit(1);
    }
}

void semSignal(int semSetId,int semNum)
{
    struct sembuf sb;
    sb.sem_num = semNum;
    sb.sem_op = 1;//表示信号量加1
    sb.sem_flg = SEM_UNDO;

    //第 3 個參數表示數組sb的大小
    if(semop(semSetId,&sb,1)<0)
    {
        perror("semSignal failed!");
        exit(1);
    }   
}

void init()
{
    //緩沖區配置設定以及初始化
    if((shmId = shmget(IPC_PRIVATE,SHM_SIZE,SHM_MODE))<0)
    {
        perror("create shared memory failed!");
        exit(1);
    }
    pSM = (struct ShM*) shmat(shmId,0,0);
    pSM->start = 0;
    pSM->end = 0;

    if((semSetId = semget(IPC_PRIVATE,3,SEM_MODE))<0)
    {
        perror("create semaphore failed!");
        exit(1);
    }

    //空閑塊數量 e
    //信号量初始化,其中 su 表示 union semun   
    su.val = size_of_buffer;//目前庫房還可以接收多少産品  
    if(semctl(semSetId,0,SETVAL, su) < 0){  
        perror("semctl failed");  
        exit(1);  
    }

    //可用數量 n
    su.val = 0;//目前沒有産品  
    if(semctl(semSetId,1,SETVAL,su) < 0){  
        perror("semctl failed");  
        exit(1);  
    }

    //權限 s  
    su.val = 1;//為1時可以進入緩沖區  
    if(semctl(semSetId,2,SETVAL,su) < 0){  
        perror("semctl failed");  
        exit(1);  
    }  
}



void produce()
{
    int last = pSM->end;
    pSM->end = (pSM->end + 1) % size_of_buffer;
    printf("PID=%d 生産 %d\n",getpid(),last);
}

void consume()
{
    int last = pSM->start;
    pSM->start = (pSM->start - 1) % size_of_buffer;
    printf("PID=%d 消耗 %d\n",getpid(),last);
}


/*
    生産者
*/
void producer()
{
    while(1)
    {
        
        semWait(semSetId,0);
        semWait(semSetId,2);
        produce();
        semSignal(semSetId,2);
        sleep(1);
        semSignal(semSetId,1);

	count -= 1;
	if(count==0)
	{
            printf("end all!\n");
	    exit(1);
	}
    }
}

/*
    消費者
*/
void consumer()
{
    while(1)
    {
        semWait(semSetId,1);//有産品才能消費
        semWait(semSetId,2);//鎖定緩沖區
        consume();
        semSignal(semSetId,2);//釋放緩沖區
        semSignal(semSetId,0);//增加空間
        sleep(2);
    }
}


int main()
{
    int child = -1;

    init();
    for(int i=1;i<=num_of_consumer;i+=1)
    {
        if((child = fork())<0)
        {
            perror("the fork failed!");
            exit(1);
        }
        else if(child==0)
        {
            printf("我是第 %d 個消費者子程序,PID=%d\n",i,getpid());
            consumer();
            break;     
        }
    }
	
    if(child>0)
    {
        producer();
    }
	return 0;
}
           

讀者和寫者

#include<unistd.h>
#include<sys/types.h>
#include<sys/sem.h>
#include<sys/mman.h>
#include<sys/ipc.h>
#include<stdio.h>
int *critical;

int createSem()//建立信号量
{
	return semget((key_t)1000,2,IPC_CREAT|0600); 
} //第二個參數是我們要建立的信号量個數


void initSignal(int semid,int index,int value)//初始化信号量 
{
	semctl(semid,index,SETVAL,value); 
} 

void make_critical()//建立緩沖區
{
	critical = mmap(NULL,10*sizeof(int),PROT_READ|
				PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);
	critical[0]=-1;//臨界區初始化為-1;	
	critical[1]=0;//讀者數量初始化為0;	
} 


void semWait(int semid,int index)//判斷目前程序是否進去緩沖區,,被占用就挂起
{
	struct sembuf sem_buf;
	sem_buf.sem_num=index;
	sem_buf.sem_op=-1;
	sem_buf.sem_flg=SEM_UNDO;
	semop(semid,&sem_buf,1);
} 

void semSignal(int semid,int index)//喚醒一個在阻塞隊列中等待的程序
{
	struct sembuf sem_buf;
	sem_buf.sem_num=index;
	sem_buf.sem_op=1;
	sem_buf.sem_flg=SEM_UNDO;
	semop(semid,&sem_buf,1);
}


void reader(int semid)
{
	while(1)
	{
		semWait(semid,1);
		critical[1]++;
		if (critical[1]==1)
			semWait(semid,0);
		semSignal(semid,1);
		printf("讀者讀到的資料是: %d\n",critical[0]);
		semWait(semid,1);
		critical[1]--;
		if (critical[1]==0)
			semSignal(semid,0);
		semSignal(semid,1);	
	}	
}
void writer(int semid)
{
	while(1)
	{
		semWait(semid,0);
		printf("寫者寫入的資料:");
		scanf("%d",&critical[0]);
		printf("寫者更新後的資料: %d\n",critical[0]);
		semSignal(semid,0);
	}
}
int main()
{
	int semid=createSem();
	initSignal(semid,0,1);//初始化控制寫者信号量W
	initSignal(semid,1,1);//初始化控制讀者信号量R
	//the critical number is init as -1 the writer will update it
	make_critical();//create critical region
	pid_t child=fork();
	if(child==0)
	{
		reader(semid);
	}
	else
	{
		writer(semid);
	}
	return 0;
}

           

說明:這份代碼有借鑒網絡上的代碼,但是出處已經不記得了。如侵權請留言删除。

繼續閱讀