1. 概述
信号量分为有名信号量(named semaphore),无名信号量(unnamed semaphore)。
(这里说的信号量主要是指semaphore.h
中的信号量)
- 有名信号量由
sem_open
打开,无名信号量由sem_init
打开. - 有名信号量通过
sem_unlink
删除, 无名信号量通过sem_destroy
删除信号量 - 有名信号量由内核持续,正是因此多个进程间才能利用它;无名信号量一般是线程之间使用,也可以搭配共享内存在多进程之间使用。
2. 函数原型
#include
// 有名信号量的操作
sem_t *sem_open(const char *, int, ...);
int sem_unlink(const char *);
int sem_close(sem_t *);
// 无名信号量的操作
int sem_init(sem_t *, int, unsigned int);
int sem_destroy(sem_t *);
// 获取信号量值
int sem_getvalue(sem_t *, int *);
// 发出信号,即释放拥有权
int sem_post(sem_t *);
// 等待信号,即获取拥有权
int sem_trywait(sem_t *);
int sem_wait(sem_t *);
3. 用信号量解生产者-消费者问题
#include
#include
#include
#include
#include
#include
#include
#define NUMBER 50000
#define CHILD 5
#define BUFSIZE 10
// critical resource
int fd;
// semaphore
sem_t* empty;
sem_t* full;
sem_t* mutex;
void comsumer() {
int buf_out = 0;
int data = 0;
int cnt = 0;
for (int k = 0; k < NUMBER / CHILD; k++) {
sem_wait(full);
sem_wait(mutex);
// fetch buf_out
lseek(fd, BUFSIZE * sizeof(int), SEEK_SET);
read(fd, (char*)&buf_out, sizeof(int));
cnt++;
lseek(fd, sizeof(int) * buf_out, SEEK_SET);
read(fd, (char*)&data, sizeof(int));
printf("%d comsume %d %d\n", getpid(), data, cnt);
fflush(stdout);
// write back
buf_out = (buf_out + 1) % BUFSIZE;
lseek(fd, BUFSIZE * sizeof(int), SEEK_SET);
write(fd, (char *)&buf_out, sizeof(int));
sem_post(mutex);
sem_post(empty);
}
printf("%d total consume %d\n", getpid(), cnt);
}
void producer() {
int buf_in = 0;
for (int i = 0 ; i < NUMBER; i++) {
sem_wait(empty);
sem_wait(mutex);
lseek(fd, buf_in * sizeof(int), SEEK_SET);
write(fd, (char*)&i, sizeof(int));
buf_in = (buf_in + 1) % BUFSIZE;
printf("produce %d\n", i);
fflush(stdout);
sem_post(mutex);
sem_post(full);
}
}
int main() {
mutex = sem_open("mutex", O_CREAT | O_EXCL, 0644, 1);
full = sem_open("full", O_CREAT | O_EXCL, 0644, 0);
empty = sem_open("empty", O_CREAT | O_EXCL, 0644, BUFSIZE);
int out_index = 0;
fd = open("buffer.dat", O_CREAT | O_RDWR | O_TRUNC, 0666);
lseek(fd, BUFSIZE * sizeof(int), SEEK_SET);
write(fd, (char *)&(out_index), sizeof(int));
pid_t p;
// create producer
if ((p = fork()) == 0) {
producer();
return 0;
} else if (p < 0){
printf("Fail to fork!\n");
return -1;
}
// create comsumer
for (int j = 0; j < CHILD ; j++)
{
if ((p = fork()) == 0) {
comsumer();
return 0;
} else if (p < 0) {
printf("Fail to fork!\n");
return -1;
}
}
int cnt = 0;
printf("wait children!\n");
pid_t pid;
while (pid = waitpid(-1, NULL, 0)) {
if (errno == ECHILD) {
break;
}
cnt ++;
printf("pid: %d end | sum: %d\n", pid, cnt);
}
sem_unlink("empty");
sem_unlink("full");
sem_unlink("mutex");
return 0;
}
编译命令:
g++ pcc.c -o test -lpthread
参考资料
[1] 信号量
[2] semaphore.h