Boost w/ C++ - 奇怪的互斥行为
Boost w/ C++ - Curious mutex behavior
我正在试验 Boost
线程,据我所知,我可以编写多线程 Boost
应用程序并在 Windows 或 Linux 中编译它,而我更熟悉的 pthreads
严格用于 *NIX 系统。
我有以下示例应用程序,which is borrowed from another SO question:
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
#define NAP_DURATION (10000UL) // 10ms
boost::mutex io_mutex;
void count(int id)
{
for (int i = 0; i < 1000; ++i)
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << "Thread ID:" << id << ": " << i << std::endl;
if (id == 1)
{
std::cout << "I'm thread " << id << " and I'm taking a short nap" << std::endl;
usleep(NAP_DURATION);
}
else
{
std::cout << "I'm thread " << id << ", I drink 100 cups of coffee and don't need a nap" << std::endl;
}
std::cout << "Thread ID:" << id << ": " << i << std::endl;
boost::thread::yield();
}
}
int main(int argc, char* argv[])
{
boost::thread thrd1( boost::bind(&count, 1));
boost::thread thrd2( boost::bind(&count, 2));
thrd1.join();
thrd2.join();
return 0;
}
我通过以下方式在我的 Ubuntu 14.04 LTS 系统上安装了 Boost:
sudo apt-get install libboost-all-dev
我通过以下方式编译上面的代码:
g++ test.cpp -lboost_system -lboost_thread -I"$BOOST_INLCUDE" -L"$BOOST_LIB"
我 运行 发现了一些有趣的矛盾之处。如果我设置一个很长的 NAP_DURATION
,比如 1 秒 (1000000
),似乎只有线程 1
在完成其操作之前获得互斥量,并且线程 [=19] 很少见=] 在线程 1
完成之前获得锁,即使我将 NAP_DURATION
设置为几毫秒也是如此。
当我使用 pthreads
编写类似的此类应用程序时,锁通常会或多或少地在线程之间随机交替,因为另一个线程已经被互斥体阻塞。
所以,对于问题:
- 这是预期的行为吗?
- 有没有办法控制这种行为,例如让作用域锁的行为就像锁定操作排队一样?
- 如果 (2) 的答案是“否”,是否可以使用
Boost
条件变量实现类似的功能而不必担心 lock/unlock 调用失败?
- 是否保证
scoped_lock
解锁?我正在使用 RAII 方法而不是手动 locking/unlocking 因为显然解锁操作可能会失败并引发异常,我正在努力使这段代码可靠。
谢谢。
澄清
我知道将调用线程置于睡眠状态不会解锁互斥量,因为它仍在范围内,但预期的调度是这样的:
- Thread1 锁定,获取互斥锁。
- Thread2 锁,块。
- Thread1 执行,释放锁,并立即尝试再次锁定。
- 线程 2 已经在等待锁,在线程 1 之前获得它。
你到底为什么感到惊讶?
如果您期望线程 2 在线程 1 休眠时获取互斥量,那么,是的,这是预期的行为,您的理解是错误的,因为您的锁在范围内。
但是如果你因为在循环迭代结束时线程 1 和线程 2 之间缺乏交替而感到惊讶,那么你可以看看 this SO question 关于调度似乎 "unfair"
Is this expected behavior?
是也不是。您不应该对哪个线程将获得互斥锁有任何期望,因为它是未指定的。但它肯定在预期行为的范围内。
Is there a way to control this behavior, such as making scoped locks behave like locking operations are queued?
不要以这种方式使用互斥锁。只是不要。只使用互斥体,这样它们相对于线程正在做的其他事情来说会保持很短的时间。
If the answer to (2) is "no", is it possible to achieve something similar with Boost condition variables and not having to worry about lock/unlock calls failing?
当然可以。编码你想要的。
Are scoped_locks guaranteed to unlock? I'm using the RAII approach rather than manually locking/unlocking because apparently the unlock operation can fail and throw an exception, and I'm trying to make this code solid.
不清楚您担心的是什么,但建议使用 RAII 方法。
我正在试验 Boost
线程,据我所知,我可以编写多线程 Boost
应用程序并在 Windows 或 Linux 中编译它,而我更熟悉的 pthreads
严格用于 *NIX 系统。
我有以下示例应用程序,which is borrowed from another SO question:
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
#define NAP_DURATION (10000UL) // 10ms
boost::mutex io_mutex;
void count(int id)
{
for (int i = 0; i < 1000; ++i)
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << "Thread ID:" << id << ": " << i << std::endl;
if (id == 1)
{
std::cout << "I'm thread " << id << " and I'm taking a short nap" << std::endl;
usleep(NAP_DURATION);
}
else
{
std::cout << "I'm thread " << id << ", I drink 100 cups of coffee and don't need a nap" << std::endl;
}
std::cout << "Thread ID:" << id << ": " << i << std::endl;
boost::thread::yield();
}
}
int main(int argc, char* argv[])
{
boost::thread thrd1( boost::bind(&count, 1));
boost::thread thrd2( boost::bind(&count, 2));
thrd1.join();
thrd2.join();
return 0;
}
我通过以下方式在我的 Ubuntu 14.04 LTS 系统上安装了 Boost:
sudo apt-get install libboost-all-dev
我通过以下方式编译上面的代码:
g++ test.cpp -lboost_system -lboost_thread -I"$BOOST_INLCUDE" -L"$BOOST_LIB"
我 运行 发现了一些有趣的矛盾之处。如果我设置一个很长的 NAP_DURATION
,比如 1 秒 (1000000
),似乎只有线程 1
在完成其操作之前获得互斥量,并且线程 [=19] 很少见=] 在线程 1
完成之前获得锁,即使我将 NAP_DURATION
设置为几毫秒也是如此。
当我使用 pthreads
编写类似的此类应用程序时,锁通常会或多或少地在线程之间随机交替,因为另一个线程已经被互斥体阻塞。
所以,对于问题:
- 这是预期的行为吗?
- 有没有办法控制这种行为,例如让作用域锁的行为就像锁定操作排队一样?
- 如果 (2) 的答案是“否”,是否可以使用
Boost
条件变量实现类似的功能而不必担心 lock/unlock 调用失败? - 是否保证
scoped_lock
解锁?我正在使用 RAII 方法而不是手动 locking/unlocking 因为显然解锁操作可能会失败并引发异常,我正在努力使这段代码可靠。
谢谢。
澄清
我知道将调用线程置于睡眠状态不会解锁互斥量,因为它仍在范围内,但预期的调度是这样的:
- Thread1 锁定,获取互斥锁。
- Thread2 锁,块。
- Thread1 执行,释放锁,并立即尝试再次锁定。
- 线程 2 已经在等待锁,在线程 1 之前获得它。
你到底为什么感到惊讶? 如果您期望线程 2 在线程 1 休眠时获取互斥量,那么,是的,这是预期的行为,您的理解是错误的,因为您的锁在范围内。
但是如果你因为在循环迭代结束时线程 1 和线程 2 之间缺乏交替而感到惊讶,那么你可以看看 this SO question 关于调度似乎 "unfair"
Is this expected behavior?
是也不是。您不应该对哪个线程将获得互斥锁有任何期望,因为它是未指定的。但它肯定在预期行为的范围内。
Is there a way to control this behavior, such as making scoped locks behave like locking operations are queued?
不要以这种方式使用互斥锁。只是不要。只使用互斥体,这样它们相对于线程正在做的其他事情来说会保持很短的时间。
If the answer to (2) is "no", is it possible to achieve something similar with Boost condition variables and not having to worry about lock/unlock calls failing?
当然可以。编码你想要的。
Are scoped_locks guaranteed to unlock? I'm using the RAII approach rather than manually locking/unlocking because apparently the unlock operation can fail and throw an exception, and I'm trying to make this code solid.
不清楚您担心的是什么,但建议使用 RAII 方法。