使用 Boost 进程间代码时的高 CSwitch(“上下文切换”)(在 Windows、Win32 上)
我正在编写一个多线程应用程序。
我使用的是 boost::interprocess 类(版本 1.36.0)
本质上,我有工作线程,当它们可以做工作时需要得到通知。
我尝试了“信号量”和“条件”方法。
在这两种情况下,工作线程的 CSwitch(上下文切换)似乎都非常高,比如每秒 600 次切换。
我看了一下代码,看起来它只是检查一个标志(原子地使用互斥体),然后在下次重试之前生成时间片。
我期望代码使用 WaitForSingleObject 或其他东西。
讽刺的是,这正是我在决定“正确”做并使用 Boost 之前所做的事情! (即使用互斥体定期检查标志的状态)。唯一的区别是,在我的方法中,我在两次检查之间睡眠了 50 毫秒,因此我没有出现高 CSwitch 问题(是的,工作在 50 毫秒内不会开始,这对我来说很好)。
几个问题:
- 这个“高”CSwitch 值重要吗?
- 如果 boost 库使用 CRITICAL_SECTIONS 而不是信号量(我不关心进程间同步 - 所有线程都在同一进程中),是否会发生这种情况?
- 如果 boost 使用 WaitForSingleObject 会发生这种情况吗?
- Boost 库中是否有另一种方法使用上述 Win32 等待方法 (WaitForXXX),我认为该方法不会受到此 CSwitch 问题的影响。
更新:这是一个伪代码示例。我无法添加真正的代码,因为它会有点复杂。但这几乎就是我正在做的事情。这只是启动一个线程来执行一次性异步活动。
注意:这些只是插图!此示例中缺少负载,例如,如果您在线程达到“等待”之前调用injectWork(),它将无法工作。我只是想说明一下我对 boost 的使用。
用法类似于:
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;
};
干杯,
约翰
I'm writing a multithreaded app.
I was using the boost::interprocess classes (version 1.36.0)
Essentially, I have worker threads that need to be notified when work is available for them to do.
I tried both the "semaphore" and "condition" approaches.
In both cases, the CSwitch (context switch) for the worker threads seemed very high, like 600 switches per second.
I had a gander at the code and it seems like it just checks a flag (atomically using a mutex) and then yields the timeslice before trying again next time.
I was expecting the code to use WaitForSingleObject or something.
Ironically, this was exactly how I was doing it before deciding to do it "properly" and use Boost! (i.e. using a mutex to check the status of a flag regularly). The only difference was, in my approach I was sleeping like 50ms between checks so I didn't have the high CSwitch problem (and yes it's fine for me that work won't start for up to 50ms).
Several questions:
- Does this "high" CSwitch value matter?
- Would this occur if the boost library was using CRITICAL_SECTIONS instead of semaphores (I don't care about inter-process syncing - all threads are in same process)?
- Would this occur if boost was using WaitForSingleObject?
- Is there another approach in the Boost libs that uses the aforementioned Win32 wait methods (WaitForXXX) which I assume won't suffer from this CSwitch issue.
Update: Here is a pseudo code sample. I can't add the real code because it would be a bit complex. But this is pretty much what I'm doing. This just starts a thread to do a one-off asynchronous activity.
NOTE: These are just illustrations! There is loads missing from this sample, e.g. if you call injectWork() before the thread has hit the "wait" it just won't work. I just wanted to illustrate my use of boost.
The usage is something like:
int main(int argc, char** args)
{
MyWorkerThread thread;
thread.startThread();
...
thread.injectWork("hello world");
}
Here is the example using 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;
};
And here was my "naive" polling code:
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;
};
Cheers,
John
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在非 POSIX 系统上,似乎
interprocess_condition
是使用循环模拟的,正如您在问题中所描述的那样。并且interprocess_semaphore
使用互斥体和interprocess_condition
进行模拟,因此 wait()-ing 最终会进入同一个循环。既然您提到不需要进程间同步,您应该查看 Boost.Thread,它提供了 条件变量。有趣的是,它似乎是在 Windows 上实现的“经典< /a>”方式,使用...信号量。
On non-POSIX systems, it seems that
interprocess_condition
is emulated using a loop, as you describe in your in question. Andinterprocess_semaphore
is emulated with a mutex and aninterprocess_condition
, so wait()-ing ends up in the same loop.Since you mention that you don't need the interprocess synchronization, you should look at Boost.Thread, which offers a portable implementation of condition variables. Amusingly, it seems that it is implemented on Windows in the "classical" way, using a... Semaphore.
如果您不介意特定于 Windows(Windows 上的较新版本),请检查 轻量条件变量CONDITION_VARIABLE(如关键部分):
If you do not mind a Windows specific (newer versions on windows), check the link for light weight condition variables CONDITION_VARIABLE (like critical sections):