我用两种方法实现了并发队列:添加(入队)和删除(出队)。

为了测试使用2个线程的实现,我在名为getRandom()的方法中生成了0到1之间的10个(NUMBER_OF_OPERATIONS)随机数。这使我可以创建不同分布的添加和删除操作。

doWork方法按线程数划分完成的工作。

问题:我从主函数传入的threadID与doWork方法接收的threadID不匹配。以下是一些示例运行:

Output 1

Output 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 Thread\n";

        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,因此您当前的代码具有不确定的行为。我可能在另一个线程读取它之前就已经超出了主线程的范围。上面的此修复程序解决了所有这些问题。

10-08 05:36