LINUX中訊號量的使用
阿新 • • 發佈:2022-04-18
1. 概述
訊號量分為有名訊號量(named semaphore),無名訊號量(unnamed semaphore)。
(這裡說的訊號量主要是指semaphore.h
中的訊號量)
- 有名訊號量由
sem_open
開啟,無名訊號量由sem_init
開啟. - 有名訊號量通過
sem_unlink
刪除, 無名訊號量通過sem_destroy
刪除訊號量 - 有名訊號量由核心持續,正是因此多個程序間才能利用它;無名訊號量一般是執行緒之間使用,也可以搭配共享記憶體在多程序之間使用。
2. 函式原型
#include <semaphore.h> // 有名訊號量的操作 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 <stdio.h> #include <semaphore.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #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