C++ 多线程。如何平等分享共同资源?
简单的代码(我知道这是一个非常糟糕的代码,但我只是为了示例而编写): 在我看来,这个输出否定了多线程的意义,因为一个线程必须等待另一个线程很长时间。这个输出应该同时给我cout of child,cout of main,cout of child,cout of main等等。我知道互斥不负责公平分享公共资源,但是:谁负责?我如何在我的程序中实现这一点 多谢各位 编辑:将std::cout放入函数:C++ 多线程。如何平等分享共同资源?,c++,multithreading,mutex,C++,Multithreading,Mutex,简单的代码(我知道这是一个非常糟糕的代码,但我只是为了示例而编写): 在我看来,这个输出否定了多线程的意义,因为一个线程必须等待另一个线程很长时间。这个输出应该同时给我cout of child,cout of main,cout of child,cout of main等等。我知道互斥不负责公平分享公共资源,但是:谁负责?我如何在我的程序中实现这一点 多谢各位 编辑:将std::cout放入函数: 10 void common_cout(string msg) { 11 mu
10 void common_cout(string msg) {
11 mu.lock();
12 std::cout << msg << std::endl;
13 mu.unlock();
14 }
10无效公共密码(字符串消息){
11亩锁();
12标准::cout
我知道互斥不负责公平分享公共资源,但是:谁负责
实际调度由操作系统完成
您还没有说明这是什么,但是在线程之间切换的频率不超过必要的频率是很常见的,因为这样效率很低(切换会有一些成本)
换句话说,你的“公平”理念-假设每个线程轮流进行严格的循环-这将是一种昂贵的默认行为。如果您想要的话,您无论如何都可以显式地对其进行编码。公平调度程序的通常目标是在可运行线程必须等待多长时间和在线程仍然运行时抢占线程的合理频率之间进行某种权衡我在做(大概)有用的工作
当然,操作系统的行为也取决于你有多少内核。你也没有提到这一点
…我如何在我的程序中实现这一点
如果你在线程中做了一些合理的实际工作,你可能会发现你的调度程序的行为更符合你的喜好。这种人工测试很少给出有用的结果,特别是因为你在一个紧密的循环中执行了少量的代码
我知道互斥不负责公平分享公共资源,但是:谁负责
实际调度由操作系统完成
您还没有说明这是什么,但是在线程之间切换的频率不超过必要的频率是很常见的,因为这样效率很低(切换会有一些成本)
换句话说,你的“公平”理念-假设每个线程轮流进行严格的循环-这将是一种昂贵的默认行为。如果您想要的话,您无论如何都可以显式地对其进行编码。公平调度程序的通常目标是在可运行线程必须等待多长时间和在线程仍然运行时抢占线程的合理频率之间进行某种权衡我在做(大概)有用的工作
当然,操作系统的行为也取决于你有多少内核。你也没有提到这一点
…我如何在我的程序中实现这一点
如果你在线程中做了一些合理的实际工作,你可能会发现你的调度程序的行为更符合你的喜好。这种人工测试很少给出有用的结果,特别是因为你在一个紧密的循环中执行了少量的代码。最初的代码在windows中也有同样的问题,但我改用本机windows等效,此windows示例以您期望的方式工作,在两个线程之间交替。ReleaseMutex()的每个实例都会导致“其他”线程获取互斥并运行。main中的Sleep(2)是确保myFunc首先启动其循环的简单方法
我还创建了一个包含main和两个线程的版本,总共有三个线程。循环是按顺序进行的,因此Windows本机互斥锁似乎是按请求的顺序完成的
对于循环类型的循环或线程和/或进程之间的一般同步,每个线程或进程使用一个信号量更好,因为任何线程或进程都可以增加(释放/信号)任何信号量。问题是信号量不是标准线程接口的本机部分,需要一些互斥和条件变量的组合来实现信号量的等效。Windows和posix支持本机信号量
#include <iostream>
#include <windows.h>
static HANDLE mu; // handle: mutex
static HANDLE ht1; // handle: thread 1
static DWORD id1; // thread 1 id
DWORD WINAPI myFunc(LPVOID) {
for (int i = 0; i < 20; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "child thread: " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
int main()
{
mu = CreateMutex(NULL,TRUE,NULL); // main owns mutex
ht1 = CreateThread(NULL, 0, myFunc, 0, 0, &id1);
Sleep(2); // make sure myFunc running
ReleaseMutex(mu); // release mutex
for (int i = 0; i < 20; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "main thread: " << i << std::endl;
ReleaseMutex(mu);
}
WaitForSingleObject(ht1, INFINITE);
CloseHandle(ht1);
CloseHandle(mu);
return 0;
}
3线程示例:
#include <iostream>
#include <windows.h>
static HANDLE mu; // handle: mutex
static HANDLE ht0; // handle: thread 0
static HANDLE ht1; // handle: thread 1
static DWORD id0; // thread 0 id
static DWORD id1; // thread 1 id
DWORD WINAPI Thread0(LPVOID) {
for (int i = 0; i < 10; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "Thread0 : " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
DWORD WINAPI Thread1(LPVOID) {
for (int i = 0; i < 10; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "Thread1 : " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
DWORD WINAPI Thread2(LPVOID) {
for (int i = 0; i < 10; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "Thread2 : " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
int main()
{
mu = CreateMutex(NULL,TRUE,NULL); // main owns mutex
ht0 = CreateThread(NULL, 0, Thread0, 0, 0, &id0);
ht1 = CreateThread(NULL, 0, Thread1, 0, 0, &id1);
Sleep(2); // let other threads get started
ReleaseMutex(mu); // release mutex
Thread2(0);
WaitForSingleObject(ht0, INFINITE);
WaitForSingleObject(ht1, INFINITE);
CloseHandle(ht0);
CloseHandle(ht1);
CloseHandle(mu);
return 0;
}
最初的代码在windows中也存在同样的问题,但我改为使用本机windows等效程序,这个windows示例按照您期望的方式工作,在两个线程之间交替。ReleaseMutex()的每个实例都会导致“另一个”线程获取互斥并运行。睡眠(2)总的来说,这是一种确保myFunc首先启动其循环的简单方法
我还创建了一个包含main和两个线程的版本,总共有三个线程。循环是按顺序进行的,因此Windows本机互斥锁似乎是按请求的顺序完成的
对于循环类型的循环或线程和/或进程之间的一般同步,每个线程或进程使用一个信号量更好,因为任何线程或进程都可以增加(释放/信号)任何信号量。问题是信号量不是标准线程接口的本机部分,需要一些互斥和条件变量的组合来实现信号量的等效。Windows和posix支持本机信号量
#include <iostream>
#include <windows.h>
static HANDLE mu; // handle: mutex
static HANDLE ht1; // handle: thread 1
static DWORD id1; // thread 1 id
DWORD WINAPI myFunc(LPVOID) {
for (int i = 0; i < 20; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "child thread: " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
int main()
{
mu = CreateMutex(NULL,TRUE,NULL); // main owns mutex
ht1 = CreateThread(NULL, 0, myFunc, 0, 0, &id1);
Sleep(2); // make sure myFunc running
ReleaseMutex(mu); // release mutex
for (int i = 0; i < 20; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "main thread: " << i << std::endl;
ReleaseMutex(mu);
}
WaitForSingleObject(ht1, INFINITE);
CloseHandle(ht1);
CloseHandle(mu);
return 0;
}
3线程示例:
#include <iostream>
#include <windows.h>
static HANDLE mu; // handle: mutex
static HANDLE ht0; // handle: thread 0
static HANDLE ht1; // handle: thread 1
static DWORD id0; // thread 0 id
static DWORD id1; // thread 1 id
DWORD WINAPI Thread0(LPVOID) {
for (int i = 0; i < 10; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "Thread0 : " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
DWORD WINAPI Thread1(LPVOID) {
for (int i = 0; i < 10; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "Thread1 : " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
DWORD WINAPI Thread2(LPVOID) {
for (int i = 0; i < 10; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "Thread2 : " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
int main()
{
mu = CreateMutex(NULL,TRUE,NULL); // main owns mutex
ht0 = CreateThread(NULL, 0, Thread0, 0, 0, &id0);
ht1 = CreateThread(NULL, 0, Thread1, 0, 0, &id1);
Sleep(2); // let other threads get started
ReleaseMutex(mu); // release mutex
Thread2(0);
WaitForSingleObject(ht0, INFINITE);
WaitForSingleObject(ht1, INFINITE);
CloseHandle(ht0);
CloseHandle(ht1);
CloseHandle(mu);
return 0;
}
你不应该让所有线程都使用相同的内存空间。这就是为什么你必须使用锁等等。将空间均等地划分,以便第一个线程将使用1/U线程的内存。在这种情况下,你甚至不需要使用锁定机制。还要检查在你的CPU上可以运行多少个线程。运行超过1个线程是没有意义的你的CPU支持。你不应该让所有线程都使用相同的内存空间。这就是为什么你必须使用锁等等。将空间平均分配,这样第一个线程将使用1/U线程的内存。在这种情况下,你甚至不需要使用锁机制。还要检查你的CPU上可以运行多少个线程。这对你来说没有意义n个线程超过CPU支持的线程数。如果线程运行在不同的内核上,则它们应该同时运行
#include <iostream>
#include <windows.h>
static HANDLE mu; // handle: mutex
static HANDLE ht0; // handle: thread 0
static HANDLE ht1; // handle: thread 1
static DWORD id0; // thread 0 id
static DWORD id1; // thread 1 id
DWORD WINAPI Thread0(LPVOID) {
for (int i = 0; i < 10; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "Thread0 : " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
DWORD WINAPI Thread1(LPVOID) {
for (int i = 0; i < 10; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "Thread1 : " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
DWORD WINAPI Thread2(LPVOID) {
for (int i = 0; i < 10; ++i) {
WaitForSingleObject(mu, INFINITE);
std::cout << "Thread2 : " << i << std::endl;
ReleaseMutex(mu);
}
return 0;
}
int main()
{
mu = CreateMutex(NULL,TRUE,NULL); // main owns mutex
ht0 = CreateThread(NULL, 0, Thread0, 0, 0, &id0);
ht1 = CreateThread(NULL, 0, Thread1, 0, 0, &id1);
Sleep(2); // let other threads get started
ReleaseMutex(mu); // release mutex
Thread2(0);
WaitForSingleObject(ht0, INFINITE);
WaitForSingleObject(ht1, INFINITE);
CloseHandle(ht0);
CloseHandle(ht1);
CloseHandle(mu);
return 0;
}
Thread0 : 0
Thread1 : 0
Thread2 : 0
Thread0 : 1
Thread1 : 1
Thread2 : 1
...
Thread0 : 9
Thread1 : 9
Thread2 : 9