#include <stdio.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h> typedef int semophore;
semophore mutex = ;
semophore cnt = ;
semophore db = ;
//char mutex[] = "mutex";
//char db[] = "db";
int semId;
void read(int cnt)
{
fprintf(stdout, "NO.%d reading...\n",cnt);
//for (int i = 0; i < 1000000; i++);
sleep();
fprintf(stdout, "NO.%d read finished.\n",cnt); }
void write()
{
fprintf(stdout, "writing...\n");
//for (int i = 0; i < 1000000; i++);
sleep();
fprintf(stdout, "write finished.\n");
} union semun {
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};
/*
struct sembuf{ //结构定义在 linux/sem.h,无需重复定义
unsigned short sem_num; //信号在信号集中的索引,0代表第一个信号,1代表第二个信号
short sem_op; //操作类型
short sem_flg; //操作标志
};
*/ /*
void p(const char *s)
{
/*
semun arg;
int tmp;
int r;
if (strcmp(s, mutex) == 0)
{
//fprintf(stdout,"mutex:%d\n",semctl(semId, 0, GETVAL, arg));
while(1){
if(semctl(semId, 0, GETVAL, arg)<=0)
wait(&r);
else break;
}
tmp = semctl(semId, 0, GETVAL, arg);
//if(tmp<=0) waitpid();
arg.val = tmp - 1;
semctl(semId, 0, SETVAL, arg);
}
else if (strcmp(s, db) == 0)
{
//fprintf(stdout,"db:%d\n",semctl(semId, 1, GETVAL, arg));
while(1){
if(semctl(semId, 1, GETVAL, arg)<=0)
wait(&r);
else break;
}
tmp = semctl(semId, 1, GETVAL, arg);
arg.val = tmp - 1;
semctl(semId, 1, SETVAL, arg);
} sembuf arg;
arg.sem_op = 1;
arg.sem_flg = IPC_UNDO;
if(strcmp(s, mutex)==0)
{
arg.sem_num = 0;
semop(semId,&arg,1);
}
else if(strcmp(s, db)==0)
{
arg.sem_num = 1;
semop(semId,&arg,1);
} }
*/
/*
void v(const char *s)
{
/*
semun arg;
int tmp;
if (strcmp(s, mutex) == 0)
{
tmp = semctl(semId, 0, GETVAL, arg);
arg.val = tmp + 1;
semctl(semId, 0, SETVAL, arg);
}
else if (strcmp(s, db) == 0)
{
tmp = semctl(semId, 1, GETVAL, arg);
arg.val = tmp + 1;
semctl(semId, 1, SETVAL, arg);
} sembuf arg;
arg.sem_op = -1;
arg.sem_flg = IPC_UNDO;
if(strcmp(s, mutex)==0)
{
arg.sem_num = 0;
semop(semId,&arg,1);
}
else if(strcmp(s, db)==0)
{
arg.sem_num = 1;
semop(semId,&arg,1);
}
}
*/ //P操作函数
int p(int index)
{
struct sembuf buf = {, -}; if (index < )
{
perror("index of array cannot equals a minus value!\n");
return -;
}
buf.sem_num = index;
if (semop(semId, &buf, ) == -)
{
perror(" a wrong operation to semaphore occurred!\n");
return -;
}
return ;
} //V操作函数
int v(int index)
{
struct sembuf buf = {, }; if (index < )
{
perror("index of array cannot equals a minus value!\n");
return -;
}
buf.sem_num = index;
if (semop(semId, &buf, ) == -)
{
perror(" a wrong operation to semaphore occurred!\n");
return -;
}
return ;
}
void* reader(void* args)
{
p(mutex);
cnt++;
if (cnt == )
{
p(db);
}
v(mutex); read(cnt); p(mutex);
cnt--;
if (cnt == )
{
v(db);
}
v(mutex);
}
void* writer(void* args)
{
p(db);
write();
v(db);
} int main()
{
semun arg; key_t key = ;
if ((key = ftok(".", )) == -)
{
perror("ftok error:");
_exit();
}
semctl(semId, , IPC_RMID, arg); //semid = semget(key, 1, IPC_CREAT|0660); if ((semId = semget(key, , IPC_CREAT | IPC_EXCL | )) >= )
{
arg.val = ;
if (semctl(semId, , SETVAL, arg) < )
{
fprintf(stdout, "semctl error %s\n", strerror(errno));
return -;
}
if (semctl(semId, , SETVAL, arg) < )
{
fprintf(stdout, "semctl error %s\n", strerror(errno));
return -;
} }
else if (errno == EEXIST)
{
semId = semget(key, , );
//fprintf(stdout,"Taskr :: errno==EEXIST\n");
arg.val = ;
if (semctl(semId, , SETVAL, arg) < )
{
fprintf(stdout, "semctl error %s\n", strerror(errno));
return -;
}
if (semctl(semId, , SETVAL, arg) < )
{
fprintf(stdout, "semctl error %s\n", strerror(errno));
return -;
}
}
else
{
fprintf(stdout, "semget error %s\n", strerror(errno));
return -;
}
pthread_t tids[];
for(int i = ; i < ; ++i)
{ //参数依次是:创建的线程id,线程参数,调用的函数,传入的函数参数
if(i== || i== || i==)
{
fprintf(stdout,"turn NO.%d want to read.\n",i);
int ret = pthread_create(&tids[i], NULL, reader, NULL);
if (ret != )
{
fprintf(stdout, "reading error\n");
}
}
else{
fprintf(stdout,"turn NO.%d want to write.\n",i);
int ret = pthread_create(&tids[i], NULL, writer, NULL);
if (ret != )
{
fprintf(stdout, "writing error\n");
}
}
} pthread_exit(NULL);
return ;
}

结果如图(读者优先):

非常感谢 @神一城 老师的指点,之前自己没有学清楚 system V 中关于信号量的内容,使用了 semctl 这种直接赋值的操作,其实这样和直接使用 int 变量再加一些条件判断实现一样,而这样就等同于没有原子性,完全没有体现出信号量的作用,只是把信号量当作了一个普通变量。

这里向之前受到错误博客内容误导的朋友道歉。

使用system V实现读者写者问题的更多相关文章

  1. System V IPC(2)-信号量

    一.概述                                                    System V信号量与System V消息队列不同.它不是用来在进程间传递数据.它主要 ...

  2. system v和posix的共享内存对比 & 共享内存位置

    参考 http://www.startos.com/linux/tips/2011012822078.html 1)Linux和所有的UNIX操作系统都允许通过共享内存在应用程序之间共享存储空间. 2 ...

  3. 读者写者问题继 读写锁SRWLock

    在<秒杀多线程第十一篇读者写者问题>文章中我们使用事件和一个记录读者个数的变量来解决读者写者问题.问题虽然得到了解决,但代码有点复杂.本篇将介绍一种新方法--读写锁SRWLock来解决这一 ...

  4. 第3章 System V IPC

    3.1 概述 System V IPC 包含:System V消息队列.System V信号量.System V共享内存. 3.2 key_t 键和 ftok函数 这三种类型的System V IPC ...

  5. glibc库详解及与POSIX,system V这些库之间关系的说明

    自己想了解下关于system v,在网上看到一篇详细的说明,与大家分享一下,原文地址http://hi.baidu.com/tekuba/item/570887775696542e5c178918 以 ...

  6. Java实现生产者消费者问题与读者写者问题

    摘要: Java实现生产者消费者问题与读者写者问题 1.生产者消费者问题 生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从 ...

  7. 消息队列接口API(posix 接口和 system v接口)

    消息队列 posix API 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.信号这种通信方式更像\"即时\"的通信方式,它要求接受信号的进程在某个时间范围内对信 ...

  8. System V 机制(转)

    引言 UNIX 内核管理的进程自主地操作,从而产生更稳定的系统.然而,每个开发人员最终都会遇到这样的情况,即其中一组进程需要与另一组进程通信,也许是为了交换数据或发送命令.这种通信称为进程间通信(In ...

  9. 从并发处理谈PHP进程间通信(二)System V IPC

    .container { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px } .conta ...

随机推荐

  1. ubuntu升级pip报cannot import name 'main'解决方法

    执行sudo vi /usr/bin/pip 将代码: from pip import main if __name__ == '__main__': sys.exit(main()) 修改为: fr ...

  2. Keras保存模型并载入模型继续训练

    我们以MNIST手写数字识别为例 import numpy as np from keras.datasets import mnist from keras.utils import np_util ...

  3. Java中Array与ArrayList的10个区别

    Array和ArrayList都是Java中两个重要的数据结构,在Java程序中经常使用.并且ArrayList在内部由Array支持,了解Java中的Array和ArrayList之间的差异对于成为 ...

  4. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 5

    18.5  使用PDO对象 PDO扩展类库为PHP访问数据库定义了一个轻量级.一致性的接口,它提供了一个数据访问抽象层,这样,无论使用什么数据库,都可以通过一致的函数执行查询和获取数据,大大简化了数据 ...

  5. Apollo的基本概念和集成实战

    基本概念 使用场景 是一个分布式的配置中心.适用于微服务: 核心功能 集中管理不同环境,不同集群的配置: 配置修改后可以实时推送到应用端: 具备规范的权限,流程治理特性: 开发技术 服务端使用spri ...

  6. 学习UML类图

    在类图中一共包含以下几种模型元素,分别是:类(class).接口(interface)以及类之间的关系. 1.类(class) 在面向对象编程中,类是对现象世界中一组具有相同特征的物体的抽象. 2.接 ...

  7. python-3.8.0 新特性之赋值表达式

    [python-3.8.0 新特性之赋值表达式] 赋值表达式的语法是这样的“ name := expression ”,形式上看和赋值语句 “ = ” 差不多,就作用上来看也雷同.也就是说 “:=” ...

  8. make 命令与 Makefile

    make 是一个工具程序,通过读取 Makefile 文件,实现自动化软件构建.虽然现代软件开发中,集成开发环境已经取代了 make,但在 Unix 环境中,make 仍然被广泛用来协助软件开发.ma ...

  9. C#数组2(多维数组)

    using System; namespace ConsoleApp3 { struct WuGong { public string Name; public int Attack; } class ...

  10. AppBoxFuture(八): 另类的ORM实现

      通常的ORM实现基于配置或注释,由反射或Emit生成相应的Sql语句,然后将Sql发送给数据库解析Sql字符串生成AST再交给优化器处理后执行,返回的数据再经由反射或Emit转换为相应的实体实例. ...