好的,我有一个具有两个附加线程的应用程序。
线程一访问对象O,并将数据插入到作为对象O的一部分的双端队列中,并增加计数器变量。
线程2访问对象O,并从双端队列中拉出并删除数据,并减小计数器变量。
事实证明这产生了意外的结果,因为一个线程告诉我双端队列中有x个元素,而另一个线程告诉我没有元素。我假设我必须使用某种同步。我试图使用信号量,由于它不起作用,我必须对它有所误解(http://msdn.microsoft.com/en-us/library/windows/desktop/ms686946(v=vs.85).aspx)。
所以我想知道如何从两个线程访问全局对象。请注意,对全局对象O的访问经常发生,因为该访问处于while循环内,这导致继续插入和轮询。 (可能的解决方案会阻止另一个线程访问该对象,从而阻止while循环吗?)
到目前为止,我仅了解信号量和互斥量,但从未使用过它们,请您多多指教。
最佳答案
当从多个线程访问一个对象且一次访问可能更改该对象时,您需要一些同步对象。对于所描述的场景,您可能想要一个执行必要的线程保护和信令的队列类。这是一个简单的实现:
#include <mutex>
#include <condition_variable>
#include <deque>
template <typename T>
class queue
{
private:
std::mutex d_mutex;
std::condition_variable d_condition;
std::deque<T> d_queue;
public:
void push(T const& value) {
{
std::unique_lock<std::mutex> lock(this->d_mutex);
d_queue.push_front(value);
}
this->d_condition.notify_one();
}
T pop() {
std::unique_lock<std::mutex> lock(this->d_mutex);
this->d_condition.wait(lock, [=]{ return !this->d_queue.empty(); });
T rc(std::move(this->d_queue.back()));
this->d_queue.pop_back();
return rc;
}
};
该代码使用C ++ 2011构造,但是可以很容易地对其进行更改以避免使用它们,而可以使用C ++ 2003构造代替,除非它们没有标准化。
关键点是:
std::mutex
用于确保仅一次线程访问一次队列。将某些内容放入队列时,将获得互斥锁,然后将对象插入队列。插入对象后,锁将自动释放并发出条件变量信号。
从队列中提取内容时,将获取互斥锁,并且线程使用条件变量等待队列为非空:如果队列中已经有内容,则条件将为
true
和wait()
会立即返回,否则线程将进入睡眠状态,直到它收到重新评估条件的信号为止。注意,由于可能会虚假唤醒条件变量,因此可能会多次评估条件。lambda通过值捕获其上下文:真正捕获的只是
this
;成员变量不能直接捕获,因为它们不是局部上下文的一部分。pop()
的结果按值返回:释放锁后,容器可能会更改,即使将它们放置在合适的位置,也无法通过引用返回对象。这有点像一个玩具示例,其主要原因是它没有关闭系统的好方法:如果线程在队列中被阻塞,它将等待直到有另一个对象。真正的实现将有某种方式表明已到关闭时间,可能会抛出
pop()
异常。另外,有时使用不强制阻塞来提取对象的队列很有用。取而代之的是,它将具有一个获取锁的函数try_pop()
,检查队列是否为非空队列,并取决于结果提取以及对象或信号失败。像这样的函数很容易实现。关于c++ - 多线程全局对象访问,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12772227/