C++:将threadID传递给函数异常
C++ : Passing threadID to function anomaly
我用两种方法实现了一个并发队列:add(入队)和remove(出队)。
为了使用 2 个线程测试我的实现,我在名为 getRandom() 的方法中生成了 10 (NUMBER_OF_OPERATIONS) 个介于 0 和 1 之间的随机数。这允许我创建不同的添加和删除操作分布。
doWork 方法按线程数拆分完成的工作。
问题: 我从主函数传入的线程 ID 与 doWork 方法接收到的线程 ID 不匹配。以下是一些示例运行:
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
进行了无序读写,您当前的代码具有未定义的行为。事实上 i 可能在其他线程读取它之前已经超出主线程的范围。上述修复解决了所有这些问题。
我用两种方法实现了一个并发队列:add(入队)和remove(出队)。
为了使用 2 个线程测试我的实现,我在名为 getRandom() 的方法中生成了 10 (NUMBER_OF_OPERATIONS) 个介于 0 和 1 之间的随机数。这允许我创建不同的添加和删除操作分布。
doWork 方法按线程数拆分完成的工作。
问题: 我从主函数传入的线程 ID 与 doWork 方法接收到的线程 ID 不匹配。以下是一些示例运行:
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
进行了无序读写,您当前的代码具有未定义的行为。事实上 i 可能在其他线程读取它之前已经超出主线程的范围。上述修复解决了所有这些问题。