【发布时间】:2017-09-06 12:40:17
【问题描述】:
我试图更好地理解 C++ 线程。我实现了一个小例子,我希望四个线程在 std::vector 内的索引区域上工作。
当然,我遇到了死锁并阅读了互斥锁和锁的使用。据我了解,一般假设是所有变量都由线程共享,除非另有明确说明(thread_local)。如果一个线程更改了任何全局数据,明智的做法是先锁定资源,对数据进行处理以避免数据竞争,然后再次解锁数据,以便其他线程可以使用它。
在我的示例中,std::cout 上的锁工作正常,线程创建正常,函数调用正常,但即使我在处理数据之前和之后实现了 data_lock,程序仍然挂起。 如果我注释掉数据操作并显示一条消息,它也可以正常工作。每次运行的输出都不一样,所以我不要发布它。
我的感觉是我错过了一些我不知道的 C++ 线程的概念(我之前使用过 MPI)。
我的问题:
- 是否有我遗漏的概念?我还需要了解/阅读哪些内容?
- 除了使用互斥锁、锁和 thread_local 来正确执行之外,还有哪些工具?
编译说明:
g++ -std=c++1y -O0 -g3 -Wall -c -fmessage-length=0 -pthread -MMD -MP -MF"src/main.d" -MT"src/main.d" - o "src/main.o" "../src/main.cpp"
代码:
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
using namespace std;
std::mutex data_lock;
std::mutex cout_lock;
void output(std::string message){
cout_lock.lock();
cout << message << endl;
cout_lock.unlock();
}
void work(std::vector<double>& data, const int s_ind, const int e_ind) {
thread_local int i = 0;
for (i = s_ind; i <= e_ind; i++) {
data_lock.lock();
data[i] = 1.0;
data_lock.unlock();
//msg("work");
}
}
int main() {
const int size = 1000;
const int cpus = 4;
const int chunksize = size / cpus;
//create Data vector
std::vector<double> dat { (size) };
//thread vector
std::vector<std::thread> threads;
//create and start threads with proper ranges (ranges tested)
for (int cpu = 0; cpu < cpus; cpu++) {
threads.push_back(std::thread(work, ref(dat), (cpu * chunksize),(((cpu + 1) * chunksize) - 1)));
output("thread created");
}
//delete threads
for (int cpu = 0; cpu < cpus; cpu++) {
threads[cpu].join();
output("thread joined");
}
return 0;
}
【问题讨论】:
-
一般来说,“即使”你使用互斥锁,你也不会陷入死锁,但是你会遇到死锁,“因为”你使用了互斥锁。如果你有一个死锁,我不确定
-
std::vector<double> dat { (size) };是一个大小为 1 的向量,具有单个元素size。修复后,它可以正常工作here,尽管这并不能证明它很好 -
IIRC 你不需要锁定访问向量的不同元素
-
除了上述问题之外,
没有包含 - 如果您能够毫无问题地编译此示例,则您的警告级别不够。我认为互斥锁的使用没有任何问题 - 但我认为没有理由使用 thread_local 变量 - 常规的本地 var 就足够了。 -
非常感谢@Passer。数组实例化似乎是个问题。
标签: c++ multithreading locking mutex deadlock