工大后院

 找回密码
 加入后院

扫一扫,访问微社区

QQ登录

只需一步,快速开始

搜索
查看: 2323|回复: 14

[讨论] 同步互斥问题

[复制链接]
发表于 2008-4-2 23:44 | 显示全部楼层 |阅读模式
一块共享内存. 有多个进程进行写操作,比如发送消息, 有一个进程进行读操作(也可以是多个),比如接收消息.
消息的长度是不定长的,应该怎样设计这个方案呢?

首先想到的是设置信号量sem, 初值为1, 并实现原子操作的lock和unlock
当需要访问shared memory时,进行lock,然后操作shared memory,操作完后,调用unlock解除信号锁.
那么消息的数据结构怎样组织才好呢? 毕竟消息长度是不定长的.
另外如果写进程是多个而读进程是一个,这样会不会读进程的调度量及不上写进程,而使shared memory很快就满.

欢迎讨论.
 楼主| 发表于 2008-4-2 23:49 | 显示全部楼层
数据结构的设计
在shared memory的头部留下一小块空间, 作为整个消息队列的头, 存放头第一条消息的指针,最后一条消息的消息尾的指针, 和消息数目.
每次操作都先访问这个head.
构建成一个循环队列...
回复

使用道具 举报

发表于 2008-4-3 13:13 | 显示全部楼层
消息长度不定长,消息总数目也不定长,只有首指针尾指针和总数目的话可以定位到第N条消息吗?
回复

使用道具 举报

发表于 2008-4-3 13:16 | 显示全部楼层
明白了,LZ指的是每条消息都留一个位置指向下一消息
回复

使用道具 举报

发表于 2008-4-3 13:20 | 显示全部楼层
“读”消息是指把消息取出并且清空相应内存吧?
能不能让读消息进程排队排在最前面(读消息的前提是有消息可读)
LZ遇到的问题有点像操作系统课程里的例子...不知是不是我理解错了。。
回复

使用道具 举报

 楼主| 发表于 2008-4-6 00:04 | 显示全部楼层
原帖由 dreamwalker 于 2008-4-3 13:13 发表
消息长度不定长,消息总数目也不定长,只有首指针尾指针和总数目的话可以定位到第N条消息吗?


初步设想是在每条消息头放置消息长度.
shared memory的总数目应该是与定位消息干系不大.
回复

使用道具 举报

 楼主| 发表于 2008-4-6 00:06 | 显示全部楼层
原帖由 dreamwalker 于 2008-4-3 13:20 发表
“读”消息是指把消息取出并且清空相应内存吧?
能不能让读消息进程排队排在最前面(读消息的前提是有消息可读)
LZ遇到的问题有点像操作系统课程里的例子...不知是不是我理解错了。。


读出来,不一定要清空内存.下次写就覆盖吧...
回复

使用道具 举报

发表于 2008-4-7 01:22 | 显示全部楼层
可否考虑这样的结构?
msgInfo
{
     msgHeader ;
     msgLength ;
     msgContent;  /* 用一块内存来保存消息的具体内容 */
}
这样,可以在msgHeader里面定义不同的消息类型之类什么的,然后不同的类型对应不同的msgContent,然后可以对应不同的type定义msgContent的内容的解析方式
这样的结构是,在读取的时候可以得到读取的地方,同时可以把内容完整地存在内存中,同时定义不同的类型的解析方式的话,就很灵活地可以定义不同的消息,


不过,溢出始终是一个问题,可不可以用多线程的方式读取?
都还没有想出怎么样的一个解决方式,只有考虑具体的应用,比如,多个进程写到这个共享内存,但是写的频率不大,这样可以考虑更大地共享内存,然后更快地读取方式(直接根据读出的length来把后面的内存的内容copy到自己的内存,然后再处理...)
回复

使用道具 举报

 楼主| 发表于 2008-4-7 22:17 | 显示全部楼层
用循环队列实现.
每条消息的首字节保存该消息的长度.
shared memory首部的全局信息如下定义:
headinfo
{
void *pFirst; //第一条可读消息的首地址
void *pLast; //最后一条消息的尾地址(也即下一条要写入的消息开始写的地址).
}
每次读时从整个shared memory的headinfo保存的pFirst所指示的地址处开始读,
写时从headinfo保存的pLast指示的地址处开始写.
其实与蝎子的做法有点类似.

关于溢出问题, 队列满时是写不进的,会返回error给调用者.

但当没有消息在shared memory时, 怎样把read process idle掉.
当有消息时,怎样wake up它?
回复

使用道具 举报

发表于 2008-4-8 22:08 | 显示全部楼层
看实现的方式了,对于read process来说,可以做成一个无限的循环,然后在循环里面读取函数,如果无消息报可读的时候就sleep一步段时间,linux直接有这样的系统函数,可以s,或者ns为单位

然后对于write process来说是一样的,同时看应用的需要,是把这个进程sleep掉等待shared memory 有空闲区域来写,还是直接丢弃这个消息,然后下次的可以直接写shared memory 而不管是否有空闲区域...

在线程的编写中通常这都是一个的无限循环,然后如果需要等待一定信号而阻塞的就用sleep等待一小段时间然后再检测是否符合条件去继续走下去
回复

使用道具 举报

 楼主| 发表于 2008-4-9 23:58 | 显示全部楼层
初定使用sleep.
到时review不通过再想其它办法了.
回复

使用道具 举报

发表于 2008-4-11 22:51 | 显示全部楼层
其实应该以实现的难度来考虑这个了,

如果要求进程通信来wakeup的话,这样肯定对于写进程和,读进程都是一个负担,要另外加消息处理的部分,但是用这个自己检查自己sleep的方式来实现的话可以各自模块更独立,进程间的交互也减少,但是应该考虑实际的应用场景以及可能的扩展....
回复

使用道具 举报

 楼主| 发表于 2008-4-11 23:37 | 显示全部楼层
sleep的难度最低了吧...

读进程的话, 我的设想是做一个线程池, 每读一条消息后, 就从池中取一个线程去处理..
回复

使用道具 举报

发表于 2008-4-12 01:44 | 显示全部楼层
so,应该在检视会议上坚持用sleep的方法..否则可能会做得很复杂,进程间交互的话,复杂度成倍上升.....
回复

使用道具 举报

 楼主| 发表于 2008-4-12 09:46 | 显示全部楼层
sleep配上alarm和信号基本上可以实现到handup和wakeup了.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入后院

本版积分规则

QQ|Archiver|手机版|小黑屋|广告业务Q|工大后院 ( 粤ICP备10013660号 )

GMT+8, 2025-5-14 11:54

Powered by Discuz! X3.5

Copyright © 2001-2024 Tencent Cloud.

快速回复 返回顶部 返回列表