#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. python有哪些优点跟缺点

    显著的优点 1. 语言简洁优美,Java能实现的python都能实现(除安卓开发),python能实现的Java不一定能实现如(自动化运维,爬虫) 2. 跨平台,window, linux,mac通用 ...

  2. IDEA springboot配置

    基于springboot2.1.7 springboot项目创建 springboot热部署 springboot配置swagger2 springboot配置mybatis springboot配置 ...

  3. Codeforces Round #602 (Div. 2, based on Technocup 2020 Elimination Round 3) E. Arson In Berland Forest 二分 前缀和

    E. Arson In Berland Forest The Berland Forest can be represented as an infinite cell plane. Every ce ...

  4. lua require路径设置实例

    1.首先要强调的是,lua require的路径用的是斜杠"/",而不是从Windows文件属性那里复制来的反斜杠"\". 2.通过 print(pagckag ...

  5. 程序员,你还不会合理选择Filter、Interceptor、Aspect?

    小伙伴们应该听说过过滤器.拦截器.切面,印象上都能够起到截断拦截的作用,在做一些业务需求时,不知道如何选择,今天老顾就来介绍一下他们之间的区别. 过滤器可以拦截到方法的请求和响应 (ServletRe ...

  6. IT兄弟连 HTML5教程 HTML文档主体标记body

    在HTML的<body>和</body>标记中定义文档的主体,包含文档的所有内容(比如文本.超链接.图像.表格和列表等等).<body>标签有自己的属性,设置< ...

  7. module.exports与exports,export与export default的区别

    首先我们要明白一个前提,CommonJS模块规范和ES6模块规范完全是两种不同的概念. CommonJS模块规范 Node应用由模块组成,采用CommonJS模块规范. 根据这个规范,每个文件就是一个 ...

  8. C# 使用Json.NET对数据进行序列化和反序列化 | c# json serialize and deserialize using json.net JsonConvert

    本文首发于个人博客https://kezunlin.me/post/22391aa3/,欢迎阅读最新内容! c# json serialize and deserialize using json.n ...

  9. ASH裸数据dba_hist_active_sess_history的分析

    之前在一则案例<记录一则enq: TX - row lock contention的分析过程>使用过这种方法. 因为最近故障处理经常会用到这类查询进行ASH裸数据的分析,下面以m_ash0 ...

  10. KiRaiseException函数逆向

    KiRaiseException函数是记录异常的最后一步,在这之后紧接着就调用KiDispatchException分发异常. 我们在逆向前,先看一下书中的介绍: 1. 概念认知: KiRaiseEx ...