2009-12-23 49 views
0

我遇到以下问题。如何添加一个项目到两个队列并保证它存在于两者之中(多线程)

我有两个类,在这种情况下,A和B,都拥有concurrent_queue。这里的假设是concurrent_queue是一个线程安全队列,具有阻塞push()函数。当一个对象在B中入队时,它访问单例A并且它也在A中排队。这样做的结果是一大堆B的队列与他们自己的对象没什么关系,而A中的一个大队列包含了他们。 B的每个实例都可以存在于一个单独的线程中。

我遇到的情况是,线程在B :: foo()中的两行代码之间经常被抢占,这意味着A :: mQueue包含该对象,但B :: mQueue尚未包含物体。

我想知道的是如何确保当调用B :: foo()时,该对象要么被推到两个队列中,要么都不推送到队列中。在我看来,我必须在A中拥有一个互斥体,B才能获得并锁定A的互斥体到B :: foo()中。

有没有人有任何建议,我怎么能做到这一点,或者我如何重组我的代码来完成这个?我正在使用boost ::线程库。

Class A 
{  
public: 
    A& instance(){/* return singleton */}   
    void addToQueue(SomeObject const& obj) 
    { 
     mQueue.push(obj); 
    }   
private: 
    concurrent_queue<SomeObject> mQueue; 
}; 

Class B 
{ 
public: 
    void foo() 
    { 
     SomeObject obj; 
     //I would like to guarantee that obj is either present in both queues or neither queue 
     A::instance().addToQueue(obj); 
     mQueue.push(obj); 
    }   
private: 
    concurrent_queue<SomeObject> mQueue; 
}; 

在我的实际应用中,它不是被在A和B排队相同的对象,而将A所有排队包含指向B的结构,这让我离队一切都在A和出队B的顺序与排队时相同,但这与问题无关。

回答

2

您需要将“将对象添加到两个队列”的操作原型化。你需要在你的两个函数调用周围有一个锁或其他类型的同步原语。删除队列中的项目也是一样。

boost::mutex看起来适合这份工作。您需要一个实例,并且需要从队列修改的任何位置访问它。因为它也将有相同的寿命为A的队列中,我建议你把它放在A,然后修改队列存取,因此看起来像是:

A::instance().lockQueue(); //calls A.mQueueAccessMutex.lock(), probably 
    A::instance().addToQueue(obj); 
    mQueue.push(obj); 
A::instance().unlockQueue(); 

或者,RAII风格:

{ 
    LockHolder lh(A::instance().getLock()); //lock called in lh's constructor 

    A::instance().addToQueue(obj); 
    mQueue.push(obj); 

    //unlock called in lh's destructor 
} 

注那么concurrent_queue将是多余的,因为没有两个线程将同时访问队列。

-

,当然,总有那么简单地颠倒你把队列中的项目的顺序将解决你的问题的几率很小。 :)

1

您可能确实需要某种形式的互斥体才能保证原子性(相对于其他应用程序而言)。 Boost :: threading确实提供互斥对象iirc,因此您可能需要查看该对象。

0

据我了解B:foo应该保证在两个队列中都加入对象,但后来对这些队列的访问应该是独立的。

在这种情况下,您应该使用某种方法来增强A,直接锁定队列或返回此队列中使用的互斥锁(我假设您的concurent_queue是基于互斥锁的)。之后,b :: foo应该先锁定这两个互斥锁,然后再推,释放这两个互斥锁。

不要忘记处理异常,f.e.如果失败添加到第二个队列应该从第一个删除。

相关问题