C :将螺纹传递到功能异常

C++ : Passing threadID to function anomaly

本文关键字:功能 异常      更新时间:2023-10-16

我实现了一个并发队列,并使用两种方法: add (enqueue)&删除(Dequeue)。

要使用2个线程测试我的实现,我以一种称为getrandom()的方法在0和1之间生成了10(number_of_operations)。这使我可以创建添加和删除操作的不同分布。

dowork 方法将线程数量完成的工作分开。

问题:我从主函数传递的螺纹ID与Dowork方法接收到的螺纹ID不匹配。这是一些示例运行:

输出1

输出2

 #define NUMBER_OF_THREADS 2
 #define NUMBER_OF_OPERATIONS 10
 int main () {
        BoundedQueue<int> bQ;
        std::vector<double> temp = getRandom();
        double* randomNumbers = &temp[0];
        std::thread myThreads[NUMBER_OF_THREADS];
        for(int i = 0; i < NUMBER_OF_THREADS; i++) {
            cout << "Thread " << i << " created.n";
            myThreads[i] = std::thread ( [&] { bQ.doWork(randomNumbers, i); });
        }
        cout << "Main Threadn";
        for(int i = 0; i < NUMBER_OF_THREADS; i++) {
            if(myThreads[i].joinable()) myThreads[i].join();
        }   
        return 0;
    }
    template <class T> void BoundedQueue<T>::doWork (double randomNumbers[], int threadID) {
        cout << "Thread ID is " << threadID << "n";
        srand(time(NULL));  
        int split = NUMBER_OF_OPERATIONS / NUMBER_OF_THREADS;   
        for (int i = threadID * split; i < (threadID * split) + split; i++) {
            if(randomNumbers[i] <= 0.5) {
                int numToAdd = rand() % 10 + 1;
                add(numToAdd);
            } 
            else {
                int numRemoved = remove();
            }
        }
    }

在这一行中,您是通过参考来捕获i的:

myThreads[i] = std::thread ( [&] { bQ.doWork(randomNumbers, i); });

这意味着,当另一个线程运行lambda时,它将获得i的最新值,而不是创建时值。取而代之的是捕获它:

myThreads[i] = std::thread ( [&, i] { bQ.doWork(randomNumbers, i); });

更糟糕的是,当您未订购并写入i时,您当前的代码具有未定义的行为。事实 i 可能在另一个线程读取它之前可能已经超出了主线程的范围。以上解决方案解决了所有这些问题。