有名信号量

mac2024-07-26  18

信号量分两种,一种是无名信号量,一种是有名信号量。无名信号量一般用于线程间同步或互斥,而有名信号量一般用于进程间同步或互斥。它们的区别和管道及命名管道的区别类似,无名信号量则直接保存在内存中,而有名信号量要求创建一个文件。

函数

#include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> /* 创建一个有名信号量 */ // 1. 当有名信号量存在时使用: sem_t *sem_open(const char *name, int oflag); // 2. 当有名信号量不存在时使用: sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value); /* 参数: name:信号量文件名。注意,不能指定路径名。因为有名信号量,默认放在/dev/shm 里,如下图: flags:sem_open() 函数的行为标志。 mode:文件权限(可读、可写、可执行)的设置。 value:信号量初始值。 */ /* 返回值: 成功:信号量的地址 失败:SEM_FAILED */ #include <semaphore.h> /* 关闭有名信号量。 */ int sem_close(sem_t *sem); /* 参数: sem:指向信号量的指针。 */ /* 返回值: 成功:0 失败:-1 */ #include <semaphore.h> /* 删除有名信号量的文件。 */ int sem_unlink(const char *name); /* 参数: name:有名信号量文件名。 */ /* 返回值: 成功:0 失败:-1 */

有名信号量的 P, V 操作和无名信号量一样,使用 int sem_wait(sem_t *sem); 和 int sem_post(sem_t *sem); 进行减操作和加操作。

用于进程间互斥

#include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <wait.h> #include <semaphore.h> void function1(sem_t* sem, char* str) { sem_wait(sem); //检测sem是否非零,非零则不阻塞,并进行减操作 while(*str != '\0') { putchar(*str); fflush(stdout); str++; sleep(1); } putchar('\n'); sem_post(sem); //对sem进行加操作 } int main() { sem_t* sem = NULL; pid_t pid = fork(); if(pid < 0) { perror("fork"); _exit(-1); } else if(pid == 0) {/* 子进程 */ /* 打开一个信号量,没有就创建 */ sem = sem_open("nameSem", O_CREAT | O_RDWR, 0666, 1); if(sem == SEM_FAILED) { perror("sem_open"); _exit(-1); } char* child_str = "Hello"; function1(sem,child_str); /* 关闭信号量 */ sem_close(sem); _exit(0); } else {/* 父进程 */ /* 打开一个信号量,没有就创建 */ sem = sem_open("nameSem", O_CREAT | O_RDWR, 0666, 1); if(sem == SEM_FAILED) { perror("sem_open"); _exit(-1); } char* parent_str = "World"; function1(sem,parent_str); /* 关闭信号量 */ sem_close(sem); wait(NULL); } /* 删除有名信号量 */ sem_unlink("nameSem"); return 0; }

如果不使用互斥,执行如下。两个单词会乱序打印。

╭─lingyun@manjaro ~/Document/codes ╰─➤ gcc exam.c -lpthread ╭─lingyun@manjaro ~/Document/codes ╰─➤ ./a.out WHoerllldo

 使用信号量互斥的情况,执行后则如下。可见,会完整输出一个单词,再输出另一个单词。

╭─lingyun@manjaro ~/Document/codes ╰─➤ gcc exam.c -lpthread ╭─lingyun@manjaro ~/Document/codes ╰─➤ ./a.out World Hello

 用于进程间同步

// exam.c #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> void function1(sem_t* sem1, sem_t* sem2, char* str) { sem_wait(sem1); //检测sem是否非零,非零则不阻塞,并进行减操作 while(*str != '\0') { putchar(*str); fflush(stdout); str++; sleep(1); } putchar('\n'); sem_post(sem2); //对sem进行加操作 } int main() { sem_t* sem1 = NULL; sem_t* sem2 = NULL; sem1 = sem_open("nameSem1", O_CREAT, 0777, 1); // sem1 设为 1 sem2 = sem_open("nameSem2", O_CREAT, 0777, 0); // sem2 设为 0,使 sem_wait(sem2) 阻塞 function1(sem1,sem2,"Hello"); return 0; } // exam2.c #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> void function2(sem_t* sem1, sem_t* sem2, char* str) { sem_wait(sem2); //检测sem是否非零,非零则不阻塞,并进行减操作 while(*str != '\0') { putchar(*str); fflush(stdout); str++; sleep(1); } putchar('\n'); sem_post(sem1); //对sem进行加操作 } int main() { sem_t* sem1 = NULL; sem_t* sem2 = NULL; sem1 = sem_open("nameSem1", O_CREAT, 0777, 1); // sem2 设为 1 sem2 = sem_open("nameSem2", O_CREAT, 0777, 0); // sem2 设为 0,使 sem_wait(sem2) 阻塞 function2(sem1,sem2,"world"); return 0; }

先执行 exam2,程序阻塞了,并未打印任何字符:

╭─lingyun@manjaro ~/Document/codes ╰─➤ gcc exam2.c -lpthread -o exam2 ╭─lingyun@manjaro ~/Document/codes ╰─➤ ./exam2

再执行 exam1,打印出了 “Hello” :

╭─lingyun@manjaro ~/Document/codes ╰─➤ gcc exam.c -lpthread -o exam1 ╭─lingyun@manjaro ~/Document/codes ╰─➤ ./exam1 Hello

在 exam1 执行完后,exam2 才会打印出 “world” :

╭─lingyun@manjaro ~/Document/codes ╰─➤ gcc exam2.c -lpthread -o exam2 ╭─lingyun@manjaro ~/Document/codes ╰─➤ ./exam2 world

 

 

最新回复(0)