多线程.如何平等地分享公共资源
Multithreading. How to equally share common resources?
简单的代码(我知道这是一个非常糟糕的代码,但我只是为了这个例子而做的):
1 #include <mutex>
2 #include <iostream>
3 #include <thread>
4
5 std::mutex mu;
6
7 void myFunc(void) {
8 for (int i = 0; i < 100; ++i) {
9 mu.lock();
10 std::cout << "CHILD Thread: " << std::this_thread::get_id() << std::endl;
11 mu.unlock();
12 }
13 }
14
15 int main()
16 {
17 std::thread thr(myFunc);
18 for (int i = 0; i < 100; ++i) {
19 mu.lock();
20 std::cout << "MAIN Thread: " << std::this_thread::get_id() << std::endl;
21 mu.unlock();
22 }
23 thr.join();
24 return 0;
25 }
返回此类输出:
1 MAIN Thread: 140581832210240
2 MAIN Thread: 140581832210240
3 MAIN Thread: 140581832210240
4 MAIN Thread: 140581832210240
5 MAIN Thread: 140581832210240
6 MAIN Thread: 140581832210240
7 MAIN Thread: 140581832210240
8 CHILD Thread: 140581814855424
9 CHILD Thread: 140581814855424
10 CHILD Thread: 140581814855424
11 CHILD Thread: 140581814855424
12 CHILD Thread: 140581814855424
13 CHILD Thread: 140581814855424
14 CHILD Thread: 140581814855424
15 CHILD Thread: 140581814855424
16 CHILD Thread: 140581814855424
17 CHILD Thread: 140581814855424
18 MAIN Thread: 140581832210240
19 MAIN Thread: 140581832210240
20 MAIN Thread: 140581832210240
21 MAIN Thread: 140581832210240
22 MAIN Thread: 140581832210240
23 CHILD Thread: 140581814855424
24 CHILD Thread: 140581814855424
25 CHILD Thread: 140581814855424
26 CHILD Thread: 140581814855424
27 CHILD Thread: 140581814855424
28 CHILD Thread: 140581814855424
29 CHILD Thread: 140581814855424
....... and so on
正如我所看到的 - 这个输出违背了多线程的意义,因为一个线程必须等待另一个线程很长时间。这个输出应该同时给我子项的cout,主子项的cout,子项的cout,主要的cout等等。我知道互斥锁不负责公平份额的公共资源,但是:谁是?我如何在我的程序中实现它?
谢谢。
编辑:将std::cout放入一个函数中:
10 void common_cout(string msg) {
11 mu.lock();
12 std::cout << msg << std::endl;
13 mu.unlock();
14 }
无济于事。
原始代码在 Windows 中存在相同的问题,但我改用本机 Windows 等效项,并且此 windows 示例按照您期望的方式工作,在两个线程之间交替。ReleaseMutex() 的每个实例都会导致"其他"线程获取互斥锁并运行。main 中的 Sleep(2) 是确保 myFunc 首先启动循环的简单方法。
我还创建了一个包含主线程和两个线程的版本,总共三个线程。循环按顺序进行,因此 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;
}
输出
child thread: 0
main thread: 0
child thread: 1
main thread: 1
...
child thread: 18
main thread: 18
child thread: 19
main thread: 19
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;
}
输出
Thread0 : 0
Thread1 : 0
Thread2 : 0
Thread0 : 1
Thread1 : 1
Thread2 : 1
...
Thread0 : 9
Thread1 : 9
Thread2 : 9
我知道互斥锁不负责公平份额的公共资源,但是:谁是?
实际计划由您的操作系统完成。
你还没有说这是什么,但通常不会在线程之间切换超过必要的频率,因为它效率低下(切换有一些成本)。
换句话说,你对"公平"的想法——大概是每个线程轮流进行的严格循环——将是一种昂贵的默认行为。无论如何,如果它是您想要的,您可以显式编码它。公平调度程序的通常目标涉及在可运行线程必须等待多长时间与在线程仍在执行(大概)有用工作时抢占线程的频率之间的某种权衡。
当然,操作系统行为还取决于您拥有的内核数量。你也没有提到这个。
。我如何在我的程序中实现它?
如果你在线程中做了一些合理的实际工作,你可能会发现你的调度程序的行为更符合你的喜好。这种人工测试很少给出有用的结果,特别是因为你在一个紧密的循环中执行少量的代码。
- 具有瞬态资源的RAII类
- c++库的公共头文件中应该包含什么
- 将公共但非静态的成员函数与ALGLIB集成
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- C++从另一个类访问公共静态向量的正确方法是什么
- 如何找到2个单链表的公共节点
- 将地址分配给本地指针后,公共对象的变量将消失
- 允许从 std::map 的密钥窃取资源?
- 参考资源文件VC++中的$(SolutionDir)
- 公共与私人继承
- 如何从另一个文件继承私有成员变量和公共函数
- 如何维护资源管理器项目视图中当前可见的项目列表
- 如何从子成员函数修改父公共成员变量
- 将 std::allocate_shared 与多态资源分配器一起使用
- 使用RAII在给定次数的迭代后重新分配资源
- 资源管理设计模式
- 为C++03编译器编写部分unique_ptr,该编译器与较新的编译器在公共代码库上运行
- 如何跨平台将二进制资源构建到程序中?
- 两个线程的公共资源 - 同步足够吗?
- 多线程.如何平等地分享公共资源