免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4053 | 回复: 8

[C++] 两个进程使用共享内存和信号量同步的问题 [复制链接]

论坛徽章:
0
发表于 2015-05-31 11:47 |显示全部楼层
本帖最后由 longshadian 于 2015-05-31 11:51 编辑

两个进程使用共享内存,共享内存中存放一个信号量。
persist进程创建共享内存和信号量,然后wait。
game进程往共享内存中写数据,然后post,唤 醒persist进程,自己wait等待persist进程处理完后唤 醒

自己。
persist进程被game进程唤 醒后dosomething,然后post,唤 醒game进程,然后本身再次wait,等待下次

被game进程唤 醒
想象中的应该这么状态。
结果persist进程第一次被game进程唤 醒dosomethin后,post后唤 醒的是自己,没有唤 醒game进程。

。。结果game进程始终处于等待中。如果persist进程sleep了,那么能正常唤 醒game进程。

网上查了下,都是抄来抄去的。翻了下<<Linux/Unix系统编程>>:
如果在sem_post()调用之前信号量的值为0,并且其他某个进程正在因等待递减这个信号量

而阻塞,那么该进程会被唤 醒,它的sem_wait()调用会继续往前执行来缔结这个信号量。
如果多个进程在sem_wait()中阻塞了,并且这些进程的调度采用的是默认的循环时间分享策略,那么哪

个进程会被唤 醒并允许递减这个信号量是不确定的(与System V信号量一样,POSIX信号量仅仅是一种同

步机制,而不是一种排队机制)

现在这种情况该怎么解释。。。求解惑

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <cstdio>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstring>
#include <string>
  1. int persist()
  2. {
  3.     const char* name = "data.smem";
  4.     int fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, 0777);
  5.         if (fd < 0) {
  6.                 printf("ERROR shm_open %d\n", fd);
  7.                 return 0;
  8.         }
  9.        
  10.         if (ftruncate(fd, 1000) == -1) {
  11.                 printf("ERROR ftruncate %d\n", errno);
  12.                 return 0;
  13.         }

  14.     void* addr = mmap(NULL, 1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  15.         if (addr == MAP_FAILED) {
  16.                 printf("ERROR mmap %d\n", errno);
  17.                 return 0;
  18.         }

  19.     if (sem_init((sem_t*)addr, 1, 0) == -1) {
  20.                 printf("ERROR sem_init %d\n", errno);
  21.         return 0;
  22.     }
  23.     sem_t* pMtx = (sem_t*)addr;
  24.     addr = (char*)addr + sizeof(sem_t);

  25.     int n = 3;
  26.     while (n--) {
  27.         sem_wait(pMtx);/////////////////////这里等待game进程同步,
  28.         write(STDOUT_FILENO, addr, 1000-sizeof(sem_t));
  29.         sem_post(pMtx);//////////[color=Red]这里应该会唤 醒game进程,结果立即唤 醒了自己,这

  30. 样就处于死循环中[/color]
  31.         //sleep(1);//////////////////[color=Red]如果这里sleep了那么能够正常唤 醒game进程

  32. [/color]
  33.     }
  34.     return 0;
  35. }
复制代码
game进程打开共享内存,往共享内存中写数据,写完后唤 醒persist。
  1. int game()
  2. {
  3.     const char* name = "data.smem";
  4.     int fd = shm_open(name, O_EXCL | O_RDWR, 0777);
  5.         if (fd < 0) {
  6.                 printf("ERROR shm_open %d\n", fd);
  7.         return 0;
  8.         }

  9.     void* addr = mmap(NULL, 1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  10.     sem_t* pMtx = (sem_t*)addr;
  11.     addr = (char*)addr + sizeof(sem_t);
  12.     std::string str = "abcdefg\n";
  13.     std::memcpy(addr, str.c_str(), str.length());
  14.     sem_post(pMtx);/////////////唤 醒persist进程

  15.     sem_wait(pMtx);////////////persist进程处理完后唤 醒自己
  16.     return 0;
  17. }
复制代码
我的是ubuntu 14.04,哪位大侠能帮我测试下该段代码

论坛徽章:
0
发表于 2015-06-01 18:33 |显示全部楼层
我这里显示程序没有问题,输出三次'abcdefg",不知道为什么在你那里有问题

论坛徽章:
0
发表于 2015-06-02 09:23 |显示全部楼层
回复 2# foolishx

在我的电脑上先运行persist进程->运行game进程->persist进程打印3次->persist进程退出->game进程退出                ///结果1
我想要的结果是运行persist进程->运行game进程->persist进程打印1次->game进程退出->persist进程阻塞                ///结果2
你的运行结果是怎么样的呢?

PS:正在开发的游戏持久层没有task时会SLEEP,然后game进程继续运行。这样倒是实现了我想要的结果2。可是测试代码显示的却是结果1,这样让我很困惑。

论坛徽章:
0
发表于 2015-06-02 11:33 |显示全部楼层
回复 3# longshadian

会不会是persist&game进程都在等待信号量,哪一个被**是不确定引起的?


   

论坛徽章:
0
发表于 2015-06-02 12:24 |显示全部楼层
回复 3# longshadian


    明白你的意思了。原因是这样的:当你的persist进程第一次被**之后,它自己先write,然后sem_post,这个sem_post的行为只是给信号量的值+1,之后,任何被这个信号量阻塞的进程都有可能被**.你这个程序来看,这时正在被阻塞的进程可能是game,也可能是persist进程,这要看内核是用什么策略来调度的。很显然,这个程序的结果是persist进程被放在阻塞队列的第一个,因此才会出现 persist进程很快被**的行为。 而如果你在persist进程的sem_post之后加入sleep()这段语句,它等于告诉内核当前进程进入等待队列,不优先调度,那么显然内核会优先调度game进程,这时game进程的sem_wait使game进程被放到等待这个信号量的队列的第一次位置,才会出现game被**的行为。

    不知道我说明白了没?你看明白了不?

论坛徽章:
0
发表于 2015-06-02 14:01 |显示全部楼层
回复 4# coolmoon_133319


    应该是这样解释了

论坛徽章:
0
发表于 2015-06-02 14:02 |显示全部楼层
本帖最后由 longshadian 于 2015-06-02 14:03 编辑

回复 5# foolishx

明白了,就是说persist进程sem_post只是让信号量+1,并没有立即**某个进程。**是由内核调度决定的。

persist进程                   game进程
sem_wait
                                sem_post
write                                sem_wait
sem_post        信号量+1
sem_wait
-----game和persist都在阻塞状态,内核调度选择了persist-----
write
sem_post
sem_wait
-------内核再次选择persist--------
......
如果是persist进程sleep了就是主动让出CPU,内核会选择game进程。俺这样理解对不对?
顺便请教下,内核调度进程有哪方面的资料可供参考?
刚翻了下<<UNP>>和<<Linux/Unix系统编程>>觉得讲的挺笼统的。

论坛徽章:
0
发表于 2015-06-02 15:08 |显示全部楼层
对,就是这么个意思,对于内核调度这块,俺也只是一知半解。估计需要详细了解一下内核实现会有帮助。。

论坛徽章:
1
射手座
日期:2014-08-04 16:49:43
发表于 2015-06-04 14:27 |显示全部楼层
内核调度本身就不存在确定性, 说白了谁优先都有可能。

所以解决 这种问题的方法是:
线程A:
sem_post        A信号
sem_wait        B信号

线程B:
sem_post        B信号
sem_wait        A信号

当然其他的方法也有很多,大家都可以分享......
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP