请问一个互斥的处理问题,谢谢。

dprk 2010-07-04 09:14:36

标准C代码来实现

有一个数组,数组元素为结构体,其中有一个bool标记量 Flag;

有两个进程 A B ;
A B 两进程是异步运行

A每次传递一个指向数组元素的指针给B,传递前将Flag设置为True;

B在接收到指针后,处理指针指向的元素,处理完 将Flag设置为False

A发送指针给B后,会再次在剩余的数组元素中寻找 Flag 为False的元素,将元素中的数据填充后,
将Flag设置为True,再传递给B。
A寻找数组中Flag 为False的元素时,采用轮询方式。

那么这样实现的话,A写标记位的时候,B不会产生冲突,但B写标记位的时候,A可能正在读(但如果读到的为True,即表示B没有处理完,那么就认为B没有处理完),这时候,需要加互斥保护么?


谢谢!!!
...全文
122 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
heartraid86 2010-07-06
  • 打赏
  • 举报
回复
(1) B没有执行完process(data),是不可能执行Flag=false的,因此A不会冲掉B没有处理完的数据。
(2) B执行完process(data),但还没有执行Flag=false,因此A也不会冲掉B已经处理完的数据。
(3) B执行完Flag=false以后,A才可能在某个时间内冲掉B已经处理完的数据。

Flag标志已经做到了A,B线程处理临界资源data的互斥操作了,应该是不会有问题的。
siumen 2010-07-06
  • 打赏
  • 举报
回复
为了避免“脏”读,这是必须加互斥的!保护临界资源!
fanster28_ 2010-07-06
  • 打赏
  • 举报
回复
仅仅是要保证避免访问冲突,原子操作足以,见1楼
[Quote=引用 6 楼 dprk 的回复:]

先谢谢各位,可能我说的不清楚;有几点补充

1、A是通过消息队列向B发送指针,所以我认为,从 B接收,到数据处理,改写标记位前是没有冲突的
这一点不知道我的看法是否有问题

2、A需要在没有使用的元素或B处理完的元素中找一个元素,填放信息,这时要轮询数组,现在想考虑轮询读操作和B改写标记位的时候是否有冲突, 这里把条件放宽,即使B处理完了,但在A读的时候B没有完成标记位的改写,仍然认为……
[/Quote]
heartraid86 2010-07-04
  • 打赏
  • 举报
回复
[Quote=引用楼主 dprk 的回复:]
。。。。。但B写标记位的时候,A可能正在读(但如果读到的为True,即表示B没有处理完,那么就认为B没有处理完),这时候,需要加互斥保护么?
[/Quote]

实际上Flag已经充当了数组元素(临界资源)的锁功能了。需要线程同步的应该是“A发送指针给B后,再由B处理”这句话。这里需要一个阻塞队列BlockingQueue来做到A,B线程间的通信。

伪代码如下(java风格):


//临界资源
Type[] array=new Type[1000];
//阻塞队列
BlockingQueue<Type> queue=new ArrayBlockingQueue<Type>(100);

//A线程:
class A extends Thread(){
public void run(){
int idx=0;
while(true){
if(!array[idx].flag){
process(array[idx].value); //A线程设置数据
queue.put(array[idx]); //将数据传递给阻塞队列,等待B线程的处理
array[idx].flag=true;
}
i=((++i)==array.size())? 0 : i;
}
}
}

//B线程:
class B extends Thread(){
public void run(){

while(true){
Type temp=queue.take(array[idx]); //取出阻塞队列中需要B线程处理的对象
process(temp); //B线程处理数据
temp.flag=false;
}
}
}



注意:BlockingQueue的put()和take()方法会自动在队列满或空的情况下阻塞相应的线程。
dprk 2010-07-04
  • 打赏
  • 举报
回复
先谢谢各位,可能我说的不清楚;有几点补充

1、A是通过消息队列向B发送指针,所以我认为,从 B接收,到数据处理,改写标记位前是没有冲突的
这一点不知道我的看法是否有问题

2、A需要在没有使用的元素或B处理完的元素中找一个元素,填放信息,这时要轮询数组,现在想考虑轮询读操作和B改写标记位的时候是否有冲突, 这里把条件放宽,即使B处理完了,但在A读的时候B没有完成标记位的改写,仍然认为B没有处理完。 这里的读写冲突,说的简单些,我就是怕导致访问冲突,导致程序崩溃,其他倒不在乎,只要A不会把B没处理完的数据冲掉即可。

就现在这两点,请各位再麻烦下,谢谢。
贝隆 2010-07-04
  • 打赏
  • 举报
回复
再设置一个标记位,标记B是否正在设置Flag,如果正在设置某一个Flag,且A又选中了该Flag,那么此次选择作废。
fanster28_ 2010-07-04
  • 打赏
  • 举报
回复
B在接收到指针后,处理指针指向的元素,处理完 将Flag设置为False;

假设处理完后要写的指针为p
用原子操作写p InterlockedExchange(p,false);

在进程A中,用InterlockedCompareExchange(p,true,false);
比较选中的指针的值是否是false,是就赋为true
这整个操作是原子的
这样可以解决你说的那种冲突 同时避免A读到false时
if(p==false){
do something.
} 但p==false还没操作前p指向的值已经被B改了
heartraid86 2010-07-04
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 leo_dengzx 的回复:]

这是典型的生产-消费关系,需要两个信号量来处理,一个是a通知b生产完成,b可以消费;另一个是b通知a消费完成,可以继续生产。

你现在的这个处理机制,相当于只有一个生产信号量的情况。而消费是否完成,a不知道,这样时序上会有问题的,比如b还在消费过程中,a又生产了一个。
[/Quote]

A生产了一个,如果队列放不下,A暂时阻塞,只有B消费完了,阻塞队列有空闲了,A才会继续生产。

所以时序上不会有问题,
leo_dengzx 2010-07-04
  • 打赏
  • 举报
回复
这是典型的生产-消费关系,需要两个信号量来处理,一个是a通知b生产完成,b可以消费;另一个是b通知a消费完成,可以继续生产。

你现在的这个处理机制,相当于只有一个生产信号量的情况。而消费是否完成,a不知道,这样时序上会有问题的,比如b还在消费过程中,a又生产了一个。

33,006

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧