将Mutex和lock_guard与C++中的向量一起使用

Using Mutex and lock_guard with a vector in C++

本文关键字:向量 一起 C++ Mutex lock guard      更新时间:2023-10-16

我是C++线程领域的新手。关于mutexlock_guard的用法,我需要你的帮助(这部分无关紧要)。我有一个主要功能和一个次要功能。

请告诉我为什么在添加lock_guard(mtx)时多线程不起作用;当我移除它时,它运行得更快,但错误。你能帮我吗?

我需要正确访问向量vec并启用线程。

#include <vector>
#include <thread>
std::mutex mtx;
void threadCall(std::vector<int> &vec, int start, int end){
std::lock_guard<std::mutex> guard(mtx);
for(int i=start; i<end; i++)
vec[i] = i;
}
void ThreadFunc(std::vector<int> vec){
std::vector<std::thread> threads(2);
threads[0] = std::thread(&threadCall, std::ref(vec), 0, 10);
threads[1] = std::thread(&threadCall, std::ref(vec), 10, 20);
threads[0].join();
threads[1].join();
}
int main(){
std::vector<int> vec(20);
ThreadFunc(vec);
return 0;
}

互斥锁阻止线程并行执行任何工作。只要你能保证每个线程不会写入向量的同一部分,你就根本不需要互斥锁。

另一个问题是通过值传递向量。你应该通过参考:

void threadCall(std::vector<int>& vec, int start, int end){
for(int i=start; i<end; i++)
vec[i] = i;
}
void ThreadFunc(std::vector<int>& vec){
std::vector<std::thread> threads(2);
threads[0] = std::thread(&threadCall, std::ref(vec), 0, 10);
threads[1] = std::thread(&threadCall, std::ref(vec), 10, 20);
threads[0].join();
threads[1].join();
}
int main(){
std::vector<int> vec(20);
ThreadFunc(vec);
}

现场演示。

首先,停止按值传递向量,传递引用。在解决了这个问题之后,您的特定示例实际上根本不需要互斥。你的矢量有一个固定的大小:

std::vector<int> vec(20);

所有元素都是从一开始就默认构建的。既然你所做的只是分配:

vec[i] = i;

矢量不会重新分配任何存储或调整其项目计数。因此,没有必要将对向量的访问锁定为一个整体。再加上每个线程都在一个单独的子范围上操作,不存在任何数据竞争。您不需要同步原语。

问题是互斥被第一个线程占用,第二个线程在释放之前无法工作。

因此,本质上,您会收到一个多线程应用程序,其中所有线程都串行地执行它们的工作。

你可以移动你的警卫进入循环

for(int i=start; i<end; i++) {
std::lock_guard<std::mutex> guard(mtx);
vec[i] = i;
}

这将使线程有可能在传递的向量上协同工作。

但是:

您需要考虑到多个线程并不总是能提高性能,因为并发!=并行性

我希望这个应用程序以这种方式实际上比单线程实现慢,因为以下内容:

  1. 线程通过mutex相互阻塞,因此一次只运行一个线程
  2. 您花费时间在线程之间的上下文切换上

解决方案理念:

如果你想真正并行地运行它,你需要让线程处理独立的数据,然后连接结果。