Я экспериментирую с потоками Boost
, поскольку, насколько мне известно, я могу написать многопоточное приложение Boost
и скомпилировать его в Windows или Linux, а pthreads
, что я более знакомо с, строго используется для систем * NIX.Boost w/C++ - Любопытное поведение мьютекса
Я следующий пример приложения, 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 с помощью:
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
когда-либо получает мьютекс, пока не завершит свою работу, и очень редко происходит то, что нить 2
получает блокировку до тех пор, пока не закончится нить 1
, даже если я установил NAP_DURATION
- всего несколько миллисекунд.
Когда я написал подобные приложения с использованием pthreads
, блокировка обычно чередуется более или менее случайным образом между потоками, поскольку другой поток уже будет заблокирован на мьютексе.
Так, на вопрос (ы):
- Это ожидаемое поведение?
- Есть ли способ управлять этим поведением, например, вести себя как заблокированные блокировки, как операции блокировки?
- Если ответ на (2) «нет», возможно ли добиться чего-то подобного с переменными состояния
Boost
и не беспокоиться о сбоях блокировки/разблокировки? - Действительно ли
scoped_lock
s гарантированно разблокировать? Я использую подход RAII, а не ручную блокировку/разблокировку, потому что, по-видимому, операция разблокировки может завершиться неудачей и вызвать исключение, и я пытаюсь сделать этот код прочным.
спасибо.
РазъясненияЯ знаю, что положить вызывающий поток спать не разблокирует мьютекс, так как он все еще находится в области видимости, но ожидаемое планирование было вдоль линий:
- thread1 блокирует, получает мьютекс.
- Thread2 замки, блоки.
- Thread1 выполняет, освобождает замок и сразу же пытается заблокировать его.
- Thread2 уже ждал на замке, получает его перед thread1.
Просто догадаться, но не 'usleep' заставляет родительский процесс спать? Возможно, попробуйте использовать 'boost :: this_thread :: sleep'. Странно, чтобы спальная нить удерживала замок. –
@JohnnyCage Это распространенное заблуждение. 'usleep' останавливает только вызов * thread *. См. Обсуждение [здесь] (http://stackoverflow.com/questions/11915292/do-sleep-functions-sleep-all-threads-or-just-the-one-who-call-it). Однако верно, что 'this_thread :: sleep' предпочтительнее – Drop
О, я знаю, что' sleep' просто приостанавливает вызывающий поток и не освобождает блокировку. Меня больше беспокоит планирование. Я бы ожидал, что поток 2, поскольку он уже блокирует блокировку, выполнит перед потоком 1, так как ему придется повторно захватить блокировку. – DevNull