使用 std::thread 函数 C++11 将指针作为参数传递

Posted

技术标签:

【中文标题】使用 std::thread 函数 C++11 将指针作为参数传递【英文标题】:Passing pointer as argument with std::thread function C++11 【发布时间】:2016-06-15 18:52:05 【问题描述】:

我想传递一个指向线程函数的指针,但它返回了

错误: 尝试使用已删除的功能 __invoke(_VSTD::move(_VSTD::get(__t)), _VSTD::move(_VSTD::get<_in...>

main中的代码片段

for (int i = 0; i < threadCount; ++i) 
    ptrTabThreads = new std::thread(checkMin, ptrTab[i]);
    ptrTabThreads->join();
    ++ptrTabThreads;

以及 checkMin 函数的代码

void checkMin(int* tab) 
    int sizeOfTable = 0;

    if (tab == ptrTab[threadCount-1])
        sizeOfTable = partSize + additionalNumbers;
    else
        sizeOfTable = partSize;       

    mt.lock();
    for (int i = 0; i < sizeOfTable; ++i) 
        if (tab[i] < minValue) 
            minValue = tab[i];
        
    
    mt.unlock(); 

其中 ptrTab 是一个指针数组:

int* ptrTab[threadCount];

完整代码为:

#include <iostream>
#include <thread>
#include <condition_variable>
#include <stdlib.h>
#include <climits>

#define threadCount 10
#define numbersCount 75
std::mutex mt;
int minValue = INT32_MAX;
int partSize, additionalNumbers;
int* ptrTab[threadCount];

void checkMin(int value);
void printTab(int *tab);

int main() 
    int tab[numbersCount];
    srand(time(NULL));

    for (int i = 0; i < numbersCount; ++i) 
        tab[i] = rand() % 1000;
        std::cout << " " << tab[i];
    

    partSize = numbersCount / threadCount;
    additionalNumbers = numbersCount % threadCount;

    for (int i = 0; i < threadCount-1; ++i) 
        int *newTab = new int[partSize];
        ptrTab[i] = newTab;
    
    int *newTab = new int[partSize+additionalNumbers];
    ptrTab[threadCount-1] = newTab;

    int copiedElements = 0;
    for (int i = 0; i < threadCount-1; ++i) 
        int *tmpTab = ptrTab[i];
        for (int j = 0; j < partSize; j++) 
            tmpTab[j] = tab[copiedElements];
            copiedElements++;
        
    
    int *tmpTab = ptrTab[threadCount-1];
    int elementsLeft = numbersCount-copiedElements;
    for (int i = 0; i < elementsLeft; ++i) 
        tmpTab[i] = tab[copiedElements];
        copiedElements++;
    

    /*for (int i = 0; i < threadCount; ++i) 
        printTab(ptrTab[i]);
    */


    //----------------------

    std::thread tabThreads[threadCount];
    std::thread *ptrTabThreads = tabThreads;

    for (int i = 0; i < threadCount; ++i) 
        ptrTabThreads = new std::thread(checkMin, ptrTab[i]);
        ptrTabThreads->join();
        ++ptrTabThreads;
    

    std::cout << "\n\n" << minValue << "\n\n";

    //for check
    std::cout << "for check: minimal value is ";
    int min = INT32_MAX;
    for (int i = 0; i < numbersCount; ++i) 
        if (tab[i] < min) 
            min = tab[i];
        
    
    std::cout << min << "\n\n";



void checkMin(int* tab) 
    int sizeOfTable = 0;

    if (tab == ptrTab[threadCount-1]) 
        sizeOfTable = partSize + additionalNumbers;
    else
        sizeOfTable = partSize;        

    mt.lock();
    for (int i = 0; i < sizeOfTable; ++i) 
        if (tab[i] < minValue) 
            minValue = tab[i];
        
    
    mt.unlock();


void printTab(int *tab) 
    for (int i = 0; i < 10; ++i) 
        std::cout << tab[i] << " ";
    
    std::cout << "\n\n";

感谢您的所有建议。

【问题讨论】:

哪行代码有错误? 请发布有关您的编译器的完整示例和信息。将缺失的变量添加到上述代码后,它在 Cygwin 上使用 g++ 5.3.0 进行了干净编译。 感谢您的 cmets!我在 OS X 上编译代码,检查后显示“Apple LLVM 版本 7.0.2 (clang-700.1.81)”。我将在几秒钟内用完整的代码编辑我的问题。 你在循环中创建线程后立即调用join(),基本上让你的应用程序变成单线程的,原因是什么? 您对 checkMin 的预先声明将 int 值作为参数而不是 int* 。这可能是问题所在吗? 【参考方案1】:

触发编译错误的直接问题就在这里:

void checkMin(int value);

这是你的函数原型,不正确-应该是

void checkMin(int* value); //<-- not the pointer.

但这不是唯一的!你的代码没有意义。看看这个片段:

std::thread tabThreads[threadCount];
std::thread *ptrTabThreads = tabThreads;

for (int i = 0; i < threadCount; ++i) 
    ptrTabThreads = new std::thread(checkMin, ptrTab[i]);
    ptrTabThreads->join();
    ++ptrTabThreads;

所有这些用指针跳转的目的是什么?您的代码中也存在泄漏,因为您正在修改从 new 获得的指针,然后再进行 deleteing 它。为什么不使用下面的简单代码?

std::array<std::thread, threadCount> tabThreads;

for (int i = 0; i < threadCount; ++i) 
    tabThreads[i] = std::thread(checkMin, ptrTab[i]);
    tabThreads[i].join();

这仍然没有实际用途(应用程序实际上仍然是单线程的,因为您在创建它后立即加入您的线程),但至少,代码是正确的。要真正做一些花哨的多线程,你的循环需要如下所示:

for (int i = 0; i < threadCount; ++i)
    tabThreads[i] = std::thread(checkMin, ptrTab[i]);

for (std::thread& t : tabThreads) // so-called range-for loop. Nice thing!
    t.join();

这将使东西并行化!

【讨论】:

@Slava,这是肯定的。我也会强调这一点。 @SergeyA 是的,你是对的 - 增加 ptrTabThreads 是不合适的。使用 std::array 的解决方案看起来更好更干净。但还有一件事我不明白 - 为什么我需要在单独的循环中加入线程? @RafałP 您的意图是让所有线程同时运行,还是希望它们一个接一个地运行? join 等待线程结束,所以你的实现只是创建一个线程,等待它结束,然后创建另一个,而不是一次启动它们。 @kfsone 当然,我的意图是同时运行它们。感谢您帮助我正确理解这个想法。

以上是关于使用 std::thread 函数 C++11 将指针作为参数传递的主要内容,如果未能解决你的问题,请参考以下文章

是否有任何理由应该将 C++ 11+ std::mutex 声明为全局变量,而不是作为函数参数传递给 std::thread ?

C++11 std::thread 和虚函数绑定

C++11:如何在 std::thread 的执行函数退出后立即加入它?

c++11的std::thread能用类的成员函数构造一个线程吗?语法怎样?

C++11 并发指南三(std::mutex 详解)

cpp►C++11标准线程库<thread>