首先,我是MT的新手,所以我为可能会说的任何愚蠢/明显的事情道歉:)
假设你有windows的这些线程回调函数:
unsigned int __stdcall ThrdFuncA(void* param)
{
std::wstring s(L"Hello World\n");
std::wcout << s;
return 0;
}
unsigned int __stdcall ThrdFuncB(void* param)
{
std::wcout << L"Hello " << L"World" << std::endl;
return 0;
}
我注意到的是,当我同时运行4个线程的ThrdFuncA并重新运行100次时,输出总是
Hello World
Hello World
Hello World
等
但是当我同时运行4个线程的ThrdFuncB并重新运行100次时,输出有时会
Hello WorldHello World
Hello World
Hello World
Hello WorldHello World
Hello World
但这引发了一些问题,特别是因为第一个版本总是有效。 这是否意味着线程在执行外部函数时从不“中断”,但总是完成该函数?这个操作系统特定吗? 什么时候一个线程“破裂”?
答案 0 :(得分:3)
抢占线程 - 你的C ++示例所具有的那种 - 在任何他们想要的地方中断。因此,它可能是巧合的,可以显示您期望的输出 - 或多或少随机。
这是抢先线程的本质:你可能能够提示(使用yield或一些等价物)这是跳转到另一个线程的好时机,而某些操作可能阻塞并触发另一个线程运行,但是你无法确定何时可以切断你的线程。
在不那么常见或流行的协作线程系统中,所有切换都是在可预测的时间完成的。这是非常方便的,但是当它很好的时候很容易意外阻止线程切换,所以它们不太受欢迎。
答案 1 :(得分:1)
要明确“休息”的含义。在具有4个处理器(每个线程一个)的真正并行系统上,线程永远不会停止执行。每个线程都主动打印到共享资源(在这种情况下是输出缓冲区),并且线程很可能会同时写入输出缓冲区,从而为您提供交错输出。
在单核系统上,在任何给定时刻,操作系统将停止一个线程并运行另一个线程。由于这种情况可能随时发生,因此发送到输出缓冲区(屏幕)的字符串数据可能会出现奇怪的间隔。
看看mutual exclusion。对于共享资源(std :: cout),您可以通过要求线程获取锁来保护代码的关键部分,以便只有一个线程可以一次访问资源。锁定是抢占式多线程系统正确性所必需的。见race conditions
答案 2 :(得分:1)
cout调用可能有一个互斥锁,因此序列化它们。如果你“计算”一个完整的“Hello World \ n”字符串,那么cout方法核心代码将不会因为锁定而被中断并从另一个线程重新进入。这导致字符串的不间断输出。
如果使用子串和换行进行多次调用,则很可能另一个线程将在调用之间锁定,因此“混合”子串和换行符。