在C ++中使用Mutex和lock_guard与向量

时间:2017-11-07 10:26:01

标签: c++ multithreading c++11

我是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;
}

3 个答案:

答案 0 :(得分:4)

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

另一个问题是你按值传递矢量。您应该通过引用传递:

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);
}

Live demo

答案 1 :(得分:4)

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

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

所有元素都是默认构建的。因为你所做的就是任务:

vec[i] = i;

矢量不会重新分配任何存储空间或调整其项目数。因此,不需要锁定对整个向量的访问。结合每个线程在单独的子范围上操作的事实,并且不存在任何数据竞争。您不需要同步原语。

答案 2 :(得分:3)

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

因此,基本上您会收到一个多线程应用程序,其中所有线程都按顺序执行其工作。

你可以将你的守卫转移到for-loop

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

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

<强> BUT:

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

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

  1. 线程以mutex相互阻塞,因此只有一个线程在时间运行
  2. 您花时间在线程之间切换上下文
  3. 解决方案IDEA:

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