C++ 互斥体防护:是否有针对对象的自动保护机制?
这种情况经常发生:我们有一些线程和一个共享对象,我们需要确保在任何时候只有一个线程可以修改该对象 好吧,显而易见的解决办法是使用C++ 互斥体防护:是否有针对对象的自动保护机制?,c++,multithreading,thread-safety,posix,C++,Multithreading,Thread Safety,Posix,这种情况经常发生:我们有一些线程和一个共享对象,我们需要确保在任何时候只有一个线程可以修改该对象 好吧,显而易见的解决办法是使用锁门做工作离开那里成语。在这种情况下,我总是使用POSIX互斥体。比如说 pthread_mutex_lock(&this->messageRW); // lock the door P_Message x = this->messageQueue.front(); // do the job this->messageQueue.po
锁门做工作离开那里成语。在这种情况下,我总是使用POSIX互斥体。比如说
pthread_mutex_lock(&this->messageRW); // lock the door
P_Message x = this->messageQueue.front(); // do the job
this->messageQueue.pop();
pthread_mutex_unlock(&this->messageRW); // get out of there
// somewhere else, in another thread
while (true) {
P_Message message;
solver->listener->recvMessage(message);
pthread_mutex_lock(&(solver->messageRW)); // lock the door
solver->messageQueue.push(message); // do the job
pthread_mutex_unlock(&(solver->messageRW)); // get out of there
sem_post(&solver->messageCount);
}
我在代码中的许多地方使用了messageQueue
。因此,最终得到了许多不雅观的锁定/解锁对。我认为应该有一种方法将messageQueue
声明为应该在线程之间共享的对象,然后线程API就可以处理锁定/解锁。我可以想到一个包装器类,或者类似的东西。尽管也可以接受其他API(boost线程或其他库),但还是首选基于POSIX的解决方案
在类似情况下,您会实施什么
针对未来读者的更新
我找到了。我想这将是C++14的一部分。在这种情况下,您可以使用boost:scoped_lock
。一旦超出范围,它就会优雅地解锁:
在这种情况下,您可以使用boost:scoped_lock
。一旦超出范围,它就会优雅地解锁:
为此,我将消息队列类的子类(is-a)或包含(has-a)到另一个强制使用互斥体的类中
这在功能上是其他语言所做的,比如Javasynchronized
关键字-它修改了要自动保护的底层对象。为此,我要么将消息队列类子类(is-a)或包含(has-a)到另一个类中,强制使用互斥锁
这是其他语言在功能上所做的,比如Javasynchronized
关键字-它修改了底层对象以自动保护。应该处理锁定的是消息队列本身
(是原子的),而不是调用代码。你需要的不仅仅是
作为互斥体,您还需要一个条件来避免竞争条件。
标准的习惯用法是:
class ScopedLock // You should already have this one anyway
{
pthread_mutex_t& myOwned;
ScopedLock( ScopedLock const& );
ScopedLock& operator=( ScopedLock const& );
public:
ScopedLock( pthread_mutex_t& owned )
: myOwned( owned )
{
pthread_mutex_lock( &myOwned );
}
~ScopedLock()
{
pthread_mutex_unlock( &myOwned );
}
};
class MessageQueue
{
std::deque<Message> myQueue;
pthread_mutex_t myMutex;
pthread_cond_t myCond;
public:
MessageQueue()
{
pthread_mutex_init( &myMutex );
pthread_cond_init( &myCond );
}
void push( Message const& message )
{
ScopedLock( myMutex );
myQueue.push_back( message );
pthread_cond_broadcast( &myCond );
}
Message pop()
{
ScopedLock( myMutex );
while ( myQueue.empty() ) {
pthread_cond_wait( &myCond, &myMutex );
}
Message results = myQueue.front();
myQueue.pop_front();
return results;
}
};
class ScopedLock//您应该已经有了这个
{
pthread_mutex_t&myOwned;
ScopedLock(ScopedLock常量&);
ScopedLock&运算符=(ScopedLock常量&);
公众:
ScopedLock(pthread\u mutex\u t&owned)
:我拥有(拥有)
{
pthread_mutex_lock(&myOwned);
}
~ScopedLock()
{
pthread_mutex_unlock(&myOwned);
}
};
类消息队列
{
std::deque myQueue;
pthread_mutex_t myMutex;
pthread_cond_t myCond;
公众:
MessageQueue()
{
pthread_mutex_init(&myMutex);
pthread_cond_init(&myCond);
}
无效推送(消息常量和消息)
{
ScopedLock(myMutex);
myQueue.push_back(消息);
pthread_cond_广播(&myCond);
}
消息弹出()
{
ScopedLock(myMutex);
while(myQueue.empty()){
pthread_cond_wait(&myCond,&myMutex);
}
消息结果=myQueue.front();
myQueue.pop_front();
返回结果;
}
};
这需要更多的错误处理,但基本结构是
在那里
当然,如果您可以使用C++11,那么最好使用
标准线程原语。(否则,我通常会建议
但是如果您已经在使用Posix线程,那么
可能需要等待转换,直到可以使用标准
线程,而不是转换两次。)但您仍然需要
互斥锁和条件。应该由消息队列本身来处理锁定
(是原子的),而不是调用代码。你需要的不仅仅是
作为互斥体,您还需要一个条件来避免竞争条件。
标准的习惯用法是:
class ScopedLock // You should already have this one anyway
{
pthread_mutex_t& myOwned;
ScopedLock( ScopedLock const& );
ScopedLock& operator=( ScopedLock const& );
public:
ScopedLock( pthread_mutex_t& owned )
: myOwned( owned )
{
pthread_mutex_lock( &myOwned );
}
~ScopedLock()
{
pthread_mutex_unlock( &myOwned );
}
};
class MessageQueue
{
std::deque<Message> myQueue;
pthread_mutex_t myMutex;
pthread_cond_t myCond;
public:
MessageQueue()
{
pthread_mutex_init( &myMutex );
pthread_cond_init( &myCond );
}
void push( Message const& message )
{
ScopedLock( myMutex );
myQueue.push_back( message );
pthread_cond_broadcast( &myCond );
}
Message pop()
{
ScopedLock( myMutex );
while ( myQueue.empty() ) {
pthread_cond_wait( &myCond, &myMutex );
}
Message results = myQueue.front();
myQueue.pop_front();
return results;
}
};
class ScopedLock//您应该已经有了这个
{
pthread_mutex_t&myOwned;
ScopedLock(ScopedLock常量&);
ScopedLock&运算符=(ScopedLock常量&);
公众:
ScopedLock(pthread\u mutex\u t&owned)
:我拥有(拥有)
{
pthread_mutex_lock(&myOwned);
}
~ScopedLock()
{
pthread_mutex_unlock(&myOwned);
}
};
类消息队列
{
std::deque myQueue;
pthread_mutex_t myMutex;
pthread_cond_t myCond;
公众:
MessageQueue()
{
pthread_mutex_init(&myMutex);
pthread_cond_init(&myCond);
}
无效推送(消息常量和消息)
{
ScopedLock(myMutex);
myQueue.push_back(消息);
pthread_cond_广播(&myCond);
}
消息弹出()
{
ScopedLock(myMutex);
while(myQueue.empty()){
pthread_cond_wait(&myCond,&myMutex);
}
消息结果=myQueue.front();
myQueue.pop_front();
返回结果;
}
};
这需要更多的错误处理,但基本结构是
在那里
当然,如果您可以使用C++11,那么最好使用
标准线程原语。(否则,我通常会建议
但是如果您已经在使用Posix线程,那么
可能需要等待转换,直到可以使用标准
线程,而不是转换两次。)但您仍然需要
一个互斥体和一个条件。为什么不创建一个包含互斥体和消息队列的类,并公开用于访问队列的公共函数以及在这些公共函数中获取和释放互斥体呢。这将从客户端代码中删除获取/发布。请勾选例如..@hmjd Yes。这就是我在问题中提到的“包装类方式”,将@hmjd建议的方法与作用域锁防护结合起来,您就有了一个很好的解决方案。听起来您想要一个并发队列。互联网上有很多这样的例子,为什么不创建一个包含互斥和消息队列的类,并公开访问队列的公共函数,在这些公共函数中获取并释放互斥文本呢。