Я пишу многопоточное приложение.
Я использовал классы boost :: interprocess (версия 1.36.0)
По сути, у меня есть рабочие потоки, о которых нужно уведомлять, когда работа доступна для них.
Я пробовал подходы "семафор" и "условие".
В обоих случаях CSwitch (переключатель контекста) для рабочих потоков казался очень высоким, например, 600 переключателей в секунду.
У меня был гандер в коде, и кажется, что он просто проверяет флаг (атомарно, используя мьютекс), а затем выдает временный интервал перед повторной попыткой в следующий раз.
Я ожидал, что код будет использовать WaitForSingleObject или что-то еще.
По иронии судьбы, именно так я и делал, прежде чем решил сделать это "правильно" и использовать Boost! (т. е. использование мьютекса для регулярной проверки статуса флага). Единственным отличием было то, что в моем подходе я спал примерно 50 мс между проверками, поэтому у меня не было проблемы с высоким переключателем CS (и да, для меня нормально, что работа не начнется до 50 мс).
Несколько вопросов:
- Имеет ли значение это "высокое" значение CSwitch?
- Это могло бы произойти, если бы библиотека повышения использовала CRITICAL_SECTIONS вместо семафоров (меня не волнует межпроцессная синхронизация - все потоки находятся в одном процессе)?
- Произойдет ли это, если boost использовал WaitForSingleObject?
- Существует ли другой подход в Boost-библиотеках, использующий вышеупомянутые методы ожидания Win32 (WaitForXXX), который, как я полагаю, не пострадает от этой проблемы CSwitch.
Обновление: Вот пример псевдокода. Я не могу добавить настоящий код, потому что он будет немного сложным. Но это в значительной степени то, что я делаю. Это просто запускает поток для выполнения одноразового асинхронного действия.
ПРИМЕЧАНИЕ: Это только иллюстрации! В этом образце отсутствуют нагрузки, например если вы вызываете injectWork () до того, как поток достигнет «ожидания», он просто не будет работать. Я просто хотел проиллюстрировать свое использование наддува.
Использование выглядит примерно так:
int main(int argc, char** args)
{
MyWorkerThread thread;
thread.startThread();
...
thread.injectWork("hello world");
}
Вот пример использования boost.
class MyWorkerThread
{
public:
/// Do work asynchronously
void injectWork(string blah)
{
this->blah = blah;
// Notify semaphore
this->semaphore->post();
}
void startThread()
{
// Start the thread (Pseudo code)
CreateThread(threadHelper, this, ...);
}
private:
static void threadHelper(void* param)
{
((MyWorkerThread*)param)->thread();
}
/// The thread method
void thread()
{
// Wait for semaphore to be invoked
semaphore->wait();
cout << blah << endl;
}
string blah;
boost::interprocess::interprocess_semaphore* semaphore;
};
А вот и мой "наивный" код опроса:
class MyWorkerThread_NaivePolling
{
public:
MyWorkerThread_NaivePolling()
{
workReady = false;
}
/// Do work asynchronously
void injectWork(string blah)
{
section.lock();
this->blah = blah;
this->workReady = true;
section.unlock();
}
void startThread()
{
// Start the thread (Pseudo code)
CreateThread(threadHelper, this, ...);
}
private:
/// Uses Win32 CriticalSection
class MyCriticalSection
{
MyCriticalSection();
void lock();
void unlock();
};
MyCriticalSection section;
static void threadHelper(void* param)
{
((MyWorkerThread*)param)->thread();
}
/// The thread method
void thread()
{
while (true)
{
bool myWorkReady = false;
string myBlah;
// See if work set
section.lock();
if (this->workReady)
{
myWorkReady = true;
myBlah = this->blah;
}
section.unlock();
if (myWorkReady)
{
cout << blah << endl;
return;
}
else
{
// No work so sleep for a while
Sleep(50);
}
}
}
string blah;
bool workReady;
};
Приветствия
John