信号量是为了防止在多个程序同时访问一个共享资源发生问题的情况下引入的。
在两个进程中对信号量控制的伪代码都是下面这样的
semaphore sv = 1;
loop forever{
p(sv);
critical code section;
v(sv);
noncritical code section;
}
下面来学习一个信号量使用的例子,在任何时候都只有一个进程可以进入临界区域
具体代码如下:
#include <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/sem.h>
using namespace std;
union semun{
int value;
struct semid_ds *buf;
unsigned short* array;
};
//定义的接口 和初始的信号量ID
static int set_semvalue(void);
static void del_semvalue(void);
static int semaphore_p(void);
static int semaphore_v(void);
static int sem_id;
int main(int argc , char* argv[])
{
int i;
int pause_time;
char op_char = '0';
srand((unsigned int)getpid());
sem_id = semget((key_t)1234 , 1 , 0666| IPC_CREAT);
if(argc > 1){
if(!set_semvalue()){
fprintf(stderr , "Failed to initialized semaphored!\n");
exit(EXIT_FAILURE);
}
op_char = 'X';
sleep(2);
}
//接下来是一个循环,进入和离开临界区10次。在每次循环的开始,首先调用semphore_p,它在程序进入临界区的时候设置信号量等级进入、
for(int i = 0 ; i < 10 ; i++){
if(!semaphore_p()) exit(EXIT_FAILURE);
printf("%c" , op_char);
fflush(stdout);
pause_time = rand() % 3;
sleep(pause_time);
printf("%c" , op_char); fflush(stdout);
//在临界区域后,调用semaphore_v将信号量设置为可用。然后等待一段随机的时间,再进下一次循环。在整个循环完成后,调用del_semaphore来清理代码
if(!semaphore_v())exit(EXIT_FAILURE);
pause_time = rand() % 2;
sleep(pause_time);
}
printf("\n %d - finished\n" , getpid());
if(argc > 1){
sleep(10);
del_semvalue();
}
exit(EXIT_SUCCESS);
//return 0;
}
static int set_semvalue(void){
//函数通过将semctl调用的commang参数设置为SETVAL来初始化信号量。在使用前必须要这样做
union semun sem_union;
sem_union.value = 1;
if(semctl(sem_id ,0, SETVAL , sem_union) == -1) return (0);
return (1);
}
static void del_semvalue(void){
//删除信号量ID
union semun sem_union;
if(semctl(sem_id ,0, IPC_RMID , sem_union) == -1)
fprintf(stderr , "Failed to delete semaphore\n");
}
static int semaphore_p(void){
//对信号量做减1的操作
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_p failed\n");
return (0);
}
return (1);
}
static int semaphore_v(void){
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(0);
}
return (1);
}
./test1 1 &
./test1
这样就可以看到两个进程一直在交替访问共享的内存啦