if 语句仅在前面有调试 cout 行(C 中的多线程)时才通过
If statement passes only when preceded by debug cout line (multi-threading in C)
我创建了这段代码,用于实时解决CPU密集型任务,并可能作为未来游戏引擎的基础。为此,我创建了一个系统,其中每个线程都会修改一个整数数组,以指示它们是否已完成当前任务。
使用超过 4 个线程运行它时出现问题。当使用 6 个或更多线程时,">if (threadone_private == threadcount(">停止工作,除非我在它之前添加这个调试行"cout <<threadone_private <<endl;">。
我无法理解为什么这个调试行对 if 条件是否按预期运行有任何影响,也无法理解为什么在使用 4 个或更少的线程时没有它就可以工作。
对于此代码,我正在使用:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <thread>
#include <atomic>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
现在这段代码最多只能计算60万亿,异步步长为30亿,非常快。
以下是代码的相关部分:
int thread_done[6] = { 0,0,0,0,0,0 };
atomic<long long int> testvar1 = 0;
atomic<long long int> testvar2 = 0;
atomic<long long int> testvar3 = 0;
atomic<long long int> testvar4 = 0;
atomic<long long int> testvar5 = 0;
atomic<long long int> testvar6 = 0;
void task1(long long int testvar, int thread_number)
{
int continue_work = 1;
for (; ; ) {
while (continue_work == 1) {
for (int i = 1; i < 3000000001; i++) {
testvar++;
}
thread_done[thread_number] = 1;
if (thread_number==0) {
testvar1 = testvar;
}
if (thread_number == 1) {
testvar2 = testvar;
}
if (thread_number == 2) {
testvar3 = testvar;
}
if (thread_number == 3) {
testvar4 = testvar;
}
if (thread_number == 4) {
testvar5 = testvar;
}
if (thread_number == 5) {
testvar6 = testvar;
}
continue_work = 0;
}
if (thread_done[thread_number] == 0) {
continue_work = 1;
}
}
}
这是主线程的相关部分:
int main() {
long long int testvar = 0;
int threadcount = 6;
int threadone_private = 0;
thread thread_1(task1, testvar, 0);
thread thread_2(task1, testvar, 1);
thread thread_3(task1, testvar, 2);
thread thread_4(task1, testvar, 3);
thread thread_5(task1, testvar, 4);
thread thread_6(task1, testvar, 5);
for (; ; ) {
if (threadcount == 0) {
for (int i = 1; i < 3000001; i++) {
testvar++;
}
cout << testvar << endl;
}
else {
while (testvar < 60000000000000) {
threadone_private = thread_done[0] + thread_done[1] + thread_done[2] + thread_done[3] + thread_done[4] + thread_done[5];
cout << threadone_private << endl;
if (threadone_private == threadcount) {
testvar = testvar1 + testvar2 + testvar3 + testvar4 + testvar5 + testvar6;
cout << testvar << endl;
thread_done[0] = 0;
thread_done[1] = 0;
thread_done[2] = 0;
thread_done[3] = 0;
thread_done[4] = 0;
thread_done[5] = 0;
}
}
}
}
}
我预计由于每个工作线程只修改数组threadone_private中的一个 int,并且由于主线程仅在所有工作线程都在等待之前读取它,因此如果(threadone_private == 线程计数(应该是防弹的......显然,每当我更改它时,我都会错过一些重要的东西:
threadone_private = thread_done[0] + thread_done[1] + thread_done[2] + thread_done[3] + thread_done[4] + thread_done[5];
cout << threadone_private << endl;
if (threadone_private == threadcount) {
对此:
threadone_private = thread_done[0] + thread_done[1] + thread_done[2] + thread_done[3] + thread_done[4] + thread_done[5];
//cout << threadone_private << endl;
if (threadone_private == threadcount) {
免责声明:并发代码非常复杂且容易出错,因此使用更高级别的抽象通常是一个好主意。有很多细节很容易在不知不觉中出错。如果你不是专家,你应该非常仔细地考虑做这种低级编程。遗憾的是,C++缺乏良好的内置高级并发构造,但有一些库可以处理这个问题。
目前还不清楚整个代码应该对我做什么。据我所知,代码是否停止完全取决于计时 - 即使您正确进行了同步 - 这是完全不确定的。您的线程可以以这样一种方式执行,即thread_done
永远不会全部正确。
但除此之外,至少还有一个正确性问题:您在没有同步的情况下读取和写入int thread_done[6] = { 0,0,0,0,0,0 };
。这是未定义的行为,因此编译器可以执行所需的操作。
可能发生的情况是,编译器看到它可以缓存threadone_private
的值,因为线程从不写入它,因此该值无法更改(合法(。对std::cout
的外部调用意味着它无法确定值不会在其背后更改,因此它必须在每次迭代中读取新值(std::cout 使用锁,这会导致大多数实现中的同步,这再次限制了编译器可以假设的内容(。
我在代码中看不到任何std::mutex,std::condition_variable或std::lock的变体。在没有这些的情况下进行多线程永远不会可靠地成功。因为每当多个线程修改相同的数据时,您需要确保在任何给定时间只有一个线程(包括主线程(可以访问该数据。
编辑:我注意到你使用原子。我对此没有任何经验,但是我知道使用互斥体可以可靠地工作。
因此,您需要使用如下所示的互斥锁锁定对该数据的每次访问(读取或写入(:
//somewhere
std::mutex myMutex;
std::condition_variable myCondition;
int workersDone = 0;
/* main thread */
createWorkerThread1();
createWorkerThread2();
{
std::unique_lock<std::mutex> lock(myMutex); //waits until mutex is locked.
while(workersDone != 2) {
myCondition.wait(lock); //the mutex is unlocked while waiting
}
std::cout << "the data is ready now" << std::endl;
} //the lock is destroyed, unlocking the mutex
/* Worker thread */
while(true) {
{
std::unique_lock<std::mutex> lock(myMutex); //waits until mutex is locked
if(read_or_modify_a_piece_of_shared_data() == DATA_FINISHED) {
break; //lock leaves the scope, unlocks the mutex
}
}
prepare_everything_for_the_next_piece_of_shared_data(); //DO NOT access data here
}
//data is processed
++workersDone;
myCondition.notify_one(); //no mutex here. This wakes up the waiting thread
我希望这能让您了解如何使用互斥体和条件变量来获得线程安全性。
免责声明:100%伪代码;)
- 在C++中使用cURL和多线程
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 如何在多线程中正确使用unique_ptr进行多态性?
- sigwait() 在多线程程序中不起作用
- 成员变量在多线程 C++ 时自行更改
- 使用 shared_ptr 在中断时结束多线程循环
- 如何正确取消析构函数中的 Boost deadline_timer(在多线程环境中)?
- 如何在大函数中编写多线程函数?
- Qt::D irectConnection在多线程环境中使用时如何工作?
- if 语句仅在前面有调试 cout 行(C 中的多线程)时才通过
- C++多线程在函数调用期间避免交错
- 如何使用多线程在OSX上安装XGBoost
- C 11多线程在神经网络中的性能非常缓慢
- 使用多线程在c++中生成mandelbrot映像.没有加速
- 使用提升多线程在后台运行函数
- 多线程在C++中进行模拟
- c++:使用多线程在控制台中移动光标
- 多线程——在不同类的方法之间传递变量
- 多线程在游戏中共享资源,需要一些想法的反馈
- 一种使用多线程在巨大树形结构中查找文件的方法