方法1
n个哲学家,n个筷子
创建一个初值为n-1
的信号量,保证最多只有n-1
个进程并发争抢资源,必有1
个筷子资源余留,可以1个进程拿到两支筷子,不会死锁。
这个方法的原子操作是拿取一个筷子的过程
#include <iostream>
#include <semaphore.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <fcntl.h>
#define N 5
using namespace std;
int main(){
int n = N;
pid_t pid;
/************* 信号量 *************/
//创建信号量,初值n-1;
char sem_name[20] = "/my_semaphore";
sem_t* sem = sem_open(sem_name, O_CREAT|O_EXCL, 0666, n-1);
if (sem == SEM_FAILED){
if (errno == EEXIST)
{
// 如果信号量已存在,尝试删除它
sem_unlink(sem_name);
// 等待sem_unlink完成,避免竞态条件
while (sem_open(sem_name, O_EXCL, 0666, n-1 )!= SEM_FAILED) {
usleep(1000); // 等待1毫秒
}
sem = sem_open(sem_name, O_CREAT|O_EXCL, 0666, n-1);
}
}
/************ 使用信号量保证拿取的原子性 ************/
sem_t* sems[N]; // 为每个筷子创建互斥量
for (int i = 0; i < n; i++) {
sprintf(sem_name, "/sem_%d", i);
sems[i] = sem_open(sems_name[i], O_CREAT | O_EXCL, 0666, 1);
if (sems[i] == SEM_FAILED){
if (errno == EEXIST)
{
// 如果信号量已存在,尝试删除它
sem_unlink(sems_name[i]);
// 等待sem_unlink完成,避免竞态条件
while (sem_open(sems_name[i], O_EXCL, 0666, n-1 )!= SEM_FAILED) {
usleep(1000); // 等待1毫秒
}
sems[i] = sem_open(sems_name[i], O_CREAT|O_EXCL, 0666, 1);
}
}
}
/********** 哲学家子进程 ***********/
int i;
//创建n个哲学家子进程
for (i = 0; i < n; i++){
pid = fork();
if(pid == 0)
break;
if (pid < 0)
perror("fork");
}
// 哲学家子进程
if(pid == 0){
// 使用信号量取得进餐权限
sem_wait(sem);
// 左右筷子编号
int l = i;
int r = (i+1)%n;
// 等待筷子
sem_wait(sems[l]);
sem_wait(sems[r]);
// 模拟进餐
sleep(1);
cout << "哲学家 " << i << " 号进餐完毕" << endl;
// 释放筷子
sem_post(sems[l]);
sem_post(sems[r]);
//释放信号量
sem_post(sem);
// 关闭信号量
if (sem_close(sem) == -1) {
perror("sem_close");
exit(1);
}
exit(0);
}
// 子进程回收
while (wait(NULL) > 0);
cout << "哲学家已都进餐完毕" << endl;
/************* 信号量回收 *************/
// 完成后关闭信号量
if (sem_close(sem) == -1) {
perror("sem_close");
exit(EXIT_FAILURE);
}
// 删除信号量(可选,如果不再需要)
if (sem_unlink(sem_name) == -1) {
perror("sem_unlink");
exit(EXIT_FAILURE);
}
// 关闭和删除信号量
for (int i = 0; i < n; i++) {
sprintf(sem_name, "/sem_%d", i);
if (sem_close(sems[i]) == -1) {
perror("sem_close");
}
if (sem_unlink(sem_name) == -1) {
perror("sem_unlink");
}
}
return 0;
}
方法2
#include <iostream>
#include <semaphore.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <fcntl.h>
#define N 5
using namespace std;
int main(){
int n = N;
pid_t pid;
char sems_name[N][20];
/************ 使用信号量保证拿取的原子性 ************/
sem_t* sems[N]; // 为每个筷子创建互斥量
for (int i = 0; i < n; i++) {
sprintf(sems_name[i], "/sem_%d", i);
sems[i] = sem_open(sems_name[i], O_CREAT | O_EXCL, 0666, 1);
if (sems[i] == SEM_FAILED){
if (errno == EEXIST)
{
// 如果信号量已存在,尝试删除它
sem_unlink(sems_name[i]);
// 等待sem_unlink完成,避免竞态条件
while (sem_open(sems_name[i], O_EXCL, 0666, n-1 )!= SEM_FAILED) {
usleep(1000); // 等待1毫秒
}
sems[i] = sem_open(sems_name[i], O_CREAT|O_EXCL, 0666, 1);
}
}
}
/********** 哲学家子进程 ***********/
int i;
//创建n个哲学家子进程
for (i = 0; i < n; i++){
pid = fork();
if(pid == 0)
break;
if (pid < 0)
perror("fork");
}
// 哲学家子进程
if(pid == 0){
// 左右筷子编号
int l = i;
int r = (i+1)%n;
// 等待筷子
if(i%2==0){
sem_wait(sems[l]);
sem_wait(sems[r]);
}else{
sem_wait(sems[r]);
sem_wait(sems[l]);
}
// 模拟进餐
sleep(1);
cout << "哲学家 " << i << " 号进餐完毕" << endl;
// 释放筷子
sem_post(sems[l]);
sem_post(sems[r]);
if (sem_close(sems[i]) == -1) {
perror("sem_close");
exit(1);
}
exit(0);
}
// 子进程回收
while (wait(NULL) > 0);
cout << "哲学家已都进餐完毕" << endl;
/************* 信号量回收 *************/
for (int i = 0; i < n; i++) {
if (sem_close(sems[i]) == -1) {
perror("sem_close");
}
if (sem_unlink(sems_name[i]) == -1) {
perror("sem_unlink");
}
}
return 0;
}
方法3
对拿两个筷子这一整个过程进行互斥操作,保证总有一个进程完整的拿到两个筷子。
#include <iostream>
#include <semaphore.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <fcntl.h>
#define N 5
using namespace std;
int main(){
int n = N;
pid_t pid;
const char* sem_name = "/my_semaphore";
char sems_name[N][20];
/************* 信号量 *************/
//创建 拿一双筷子这个过程 的互斥量
sem_t* sem = sem_open(sem_name, O_CREAT|O_EXCL, 0666, 1);
if (sem == SEM_FAILED){
if (errno == EEXIST)
{
// 如果信号量已存在,尝试删除它
sem_unlink(sem_name);
// 等待sem_unlink完成,避免竞态条件
while (sem_open(sem_name, O_EXCL, 0666, n-1 )!= SEM_FAILED) {
usleep(1000); // 等待1毫秒
}
sem = sem_open(sem_name, O_CREAT|O_EXCL, 0666, n-1);
}
}
/************ 使用信号量保证拿取的原子性 ************/
sem_t* sems[N]; // 为每个筷子创建互斥量
for (int i = 0; i < n; i++) {
sprintf(sems_name[i], "/sem_%d", i);
sems[i] = sem_open(sems_name[i], O_CREAT | O_EXCL, 0666, 1);
if (sems[i] == SEM_FAILED){
if (errno == EEXIST)
{
// 如果信号量已存在,尝试删除它
sem_unlink(sem_name);
// 等待sem_unlink完成,避免竞态条件
while (sem_open(sem_name, O_EXCL, 0666, n-1 )!= SEM_FAILED) {
usleep(1000); // 等待1毫秒
}
sems[i] = sem_open(sem_name, O_CREAT|O_EXCL, 0666, 1);
}
}
}
/********** 哲学家子进程 ***********/
int i;
//创建n个哲学家子进程
for (i = 0; i < n; i++){
pid = fork();
if(pid == 0)
break;
if (pid < 0)
perror("fork");
}
// 哲学家子进程
if(pid == 0){
// 使用信号量取得拿一双筷子权限
sem_wait(sem);
// 左右筷子编号
int l = i;
int r = (i+1)%n;
// 等待筷子
sem_wait(sems[l]);
sem_wait(sems[r]);
// 模拟进餐
sleep(1);
cout << "哲学家 " << i << " 号进餐完毕" << endl;
// 释放筷子
sem_post(sems[l]);
sem_post(sems[r]);
//释放拿一双筷子这个过程 的信号量
sem_post(sem);
// 子进程关闭信号量
if (sem_close(sem) == -1) {
perror("sem_close");
exit(1);
}
if (sem_close(sems[i]) == -1) {
perror("sem_close");
exit(1);
}
exit(0);
}
// 子进程回收
while (wait(NULL) > 0);
cout << "哲学家已都进餐完毕" << endl;
/************* 信号量回收 *************/
// 完成后关闭信号量
if (sem_close(sem) == -1) {
perror("sem_close");
exit(EXIT_FAILURE);
}
if (sem_unlink(sem_name) == -1) {
perror("sem_unlink");
exit(EXIT_FAILURE);
}
for (int i = 0; i < n; i++) {
if (sem_close(sems[i]) == -1) {
perror("sem_close");
}
if (sem_unlink(sems_name[i]) == -1) {
perror("sem_unlink");
}
}
return 0;
}
标签:11,进餐,name,int,pid,2.3,sem,include,sems
From: https://www.cnblogs.com/qiuliw/p/18570330