使用可变数量的std :: thread引用的问题

时间:2017-07-13 20:13:49

标签: c++ multithreading c++11 stdthread

我已经使用了posix线程(pthread),但我尝试了标准的C ++ 11线程(很可能也是下面的pthread)。我在这里和其他论坛上发了几个帖子,但我无法弄清楚我的问题。如果有人能发光,我会很高兴。

问题是我试图将数据传递给线程,修改内部数据,并且在抛出的线程完成(加入)之后主线程必须看到修改。问题是在某些线程中数据(int)未正确读取,因此输出结果不正确。

我可以编写的用于复制问题的最小代码是:

#include <iostream>
#include <vector>
#include <thread>

using namespace std;

void threadCallbackInt(int const & x)
{
    int & y = const_cast<int &>(x);
    y += 10;
    std::cout<<"Inside Thread x = "<<y << " at position = " << &y <<std::endl;
}

int main(int argc, char* argv[])
{
    unsigned int nthreads = 3;
    vector<int> ints;
    vector<std::thread> threads(nthreads);
    threads.reserve(nthreads);
    for(unsigned int i = 0; i < nthreads; i++){
        ints.push_back(i);

        std::cout<<"In Main Thread : Before Thread Start x = "<<ints.at(i)<< " at position = " << &ints.at(i) << std::endl;
        threads[i] = std::thread(threadCallbackInt,std::ref(ints[i]));
    }

    cout << "size = " << threads.size() << endl;

    for(unsigned int i = 0; i < nthreads; i++){
        threads[i].join();
    }

    for(unsigned int i = 0; i < nthreads; i++){
        std::cout<<"In Main Thread : After Thread Start x = "<<ints[i]<< " at position = " << &ints[i] << std::endl;
    }
    return 0;
}

在几个论坛上有几个类似的帖子,但我认为是我问题的壁橱就是那个C++ 11 std::thread strange behavior

的帖子

请注意,我使用方法保留以避免引用失效和数字,但无济于事。

取决于执行,我得到不同的输出。这是产出之一:

  

在主线程中:在线程开始之前x = 0在位置= 0x21d7c40

     

在主线程中:在线程开始之前x = 1在位置= 0x21d81e4

     

在主线程中:在线程开始之前x = 2在位置= 0x21d7c48

     

内部线程x = 10,位置= 0x21d81e4

     

size = 3

     

内部线程x = 12位置= 0x21d7c48

     

内部线程x = 10,位置= 0x21d7c40

     

在主线程中:线程开始后x = 10,位置= 0x21d7c40

     

在主线程中:线程开始后x = 1,位置= 0x21d7c44

     

在主线程中:线程开始后x = 12,位置= 0x21d7c48

请注意,即使在线程完成后,其中一个x仍未更新。这是因为用于它的内存不是正确的(在线程之前它是0x21d81e4,之后是0x21d7c40)。如果您运行代码,您将看到结果不同,并且在参考不匹配的任何时候,我得到错误的结果。

任何关于可能的解决方案的亮点都将非常受欢迎。对不起,如果这篇文章是重复的(我找不到这个确切问题的实际答案)。但如果是,请说明原始帖子。

2 个答案:

答案 0 :(得分:2)

执行ints.push_back(i)后,[0]的地址正在改变。 在打印'In Main Thread ...'之前添加std::cout << "ints.size()=" << ints.size() << " &ints[0]=" << &ints[0] << endl;,输出如下(我使用Visual Studio 2017测试代码并添加了EnterCriticalSection / LeaveCriticalSection以使输出不会混淆。)

ints.size()=1 &ints[0]=0095BA28
In Main Thread : Before Thread Start x = 0 at position = 0095BA28
Inside Thread x = 10 at position = 0095BA28
ints.size()=2 &ints[0]=0095BA38
In Main Thread : Before Thread Start x = 1 at position = 0095BA3C
Inside Thread x = 11 at position = 0095BA3C
ints.size()=3 &ints[0]=0095E940
In Main Thread : Before Thread Start x = 2 at position = 0095E948
Inside Thread x = 12 at position = 0095E948
size = 3
In Main Thread : After Thread Start x = 10 at position = 0095E940
In Main Thread : After Thread Start x = 11 at position = 0095E944
In Main Thread : After Thread Start x = 12 at position = 0095E948

调整vector对象的大小,int [0]指向新分配的对象。 因此添加ints.reserve(nthreads);会保留指向int向量的指针。

ints.size()=1 &ints[0]=00DD8608
In Main Thread : Before Thread Start x = 0 at position = 00DD8608
Inside Thread x = 10 at position = 00DD8608
ints.size()=2 &ints[0]=00DD8608
In Main Thread : Before Thread Start x = 1 at position = 00DD860C
Inside Thread x = 11 at position = 00DD860C
ints.size()=3 &ints[0]=00DD8608
In Main Thread : Before Thread Start x = 2 at position = 00DD8610
Inside Thread x = 12 at position = 00DD8610
size = 3
In Main Thread : After Thread Start x = 10 at position = 00DD8608
In Main Thread : After Thread Start x = 11 at position = 00DD860C
In Main Thread : After Thread Start x = 12 at position = 00DD8610

答案 1 :(得分:0)

std::ref(ints[i])调整ints时,参考ints.push_back(i);无效。如果您希望以这种方式执行此操作,则还需要在reserve上使用ints

使用gcc进行测试,

  • i == 0时,ints.capacity() == 1
  • i == 1时,ints.capacity() == 2
  • i == 2时,ints.capacity() == 4

这表明调整大小确实正在发生。

相关问题