C++ If语句仅在前面有debug cout行时通过(C中的多线程)

C++ If语句仅在前面有debug cout行时通过(C中的多线程),c++,multithreading,C++,Multithreading,我创建了这段代码,用于实时解决CPU密集型任务,并可能作为未来游戏引擎的基础。为此,我创建了一个系统,其中有一个int数组,每个线程都会修改该数组,以表示它们是否完成了当前任务 使用4个以上的线程运行时会出现问题。当使用6个或更多线程时,除非添加此调试行,否则“if(threadone\u private==threadcount)”将停止工作“cout我在代码中看不到任何std::mutex、std::condition\u变量或std::lock的变体。如果没有以上任何一项,则执行多线程将永

我创建了这段代码,用于实时解决CPU密集型任务,并可能作为未来游戏引擎的基础。为此,我创建了一个系统,其中有一个int数组,每个线程都会修改该数组,以表示它们是否完成了当前任务


使用4个以上的线程运行时会出现问题。当使用6个或更多线程时,除非添加此调试行,否则“if(threadone\u private==threadcount)”将停止工作“cout我在代码中看不到任何std::mutex、std::condition\u变量或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
//某处
std::mutex myMutex;
std::条件变量真菌病;
int workersDone=0;
/*主线*/
createWorkerThread1();
createWorkerThread2();
{
std::unique_lock lock(myMutex);//等待直到锁定互斥锁。
while(workersDone!=2){
myCondition.wait(lock);//在等待时,互斥锁被解锁
}

std::cout我在代码中看不到任何std::mutex、std::condition\u变量或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
//某处
std::mutex myMutex;
std::条件变量真菌病;
int workersDone=0;
/*主线*/
createWorkerThread1();
createWorkerThread2();
{
std::unique_lock lock(myMutex);//等待直到锁定互斥锁。
while(workersDone!=2){
myCondition.wait(lock);//在等待时,互斥锁被解锁
}

STD::CUT< P>免责声明:并发代码非常复杂,容易出错,所以使用高级抽象通常是一个好主意。有很多细节很容易出错,而不必注意。如果你不是专家,你应该非常仔细地考虑做这样的低级编程。C++很不好。内置的高级并发构造,但是有一些库可以处理这个问题

现在还不清楚整个代码到底应该对我做什么。就我所知,代码是否会停止完全依赖于时间——即使你正确地进行了同步——这是完全不确定的。你的线程可以以这样一种方式执行,
thread\u done
永远都不是真的

但除此之外,至少还有一个正确性问题:在没有同步的情况下,您正在读取和写入
int-thread_-done[6]={0,0,0,0,0};
。这是未定义的行为,因此编译器可以执行它想要的操作


可能发生的情况是,编译器看到它可以缓存
threadone\u private
的值,因为线程从未写入该值,因此该值不能更改(合法)。对
std::cout
的外部调用意味着它不能确定该值在背后没有更改,因此它必须在每次新的迭代中读取该值(另外,std::cout在大多数实现中使用锁,这会导致同步,这又限制了编译器的假设)虽然C++并发代码很复杂,容易出错,但使用高级抽象是一个好主意。有很多细节都很容易出错,如果你不是专家,你应该非常仔细地考虑做这样的低级编程。-在高级并发构造中,但是有一些库可以处理这个问题

现在还不清楚整个代码到底应该对我做什么。就我所知,代码是否会停止完全依赖于时间——即使你正确地进行了同步——这是完全不确定的。你的线程可以以这样一种方式执行,
thread\u done
永远都不是真的

但除此之外,至少还有一个正确性问题:在没有同步的情况下,您正在读取和写入
int-thread_-done[6]={0,0,0,0,0};
。这是未定义的行为,因此编译器可以执行它想要的操作


可能发生的情况是,编译器看到它可以缓存
threadone\u private
的值,因为线程从未写入该值,因此该值不能更改(合法)。对
std::cout
的外部调用意味着它不能确定该值在背后没有更改,因此它必须在每次新的迭代中读取该值(另外,std::cout在大多数实现中使用锁,这会导致同步,这又限制了编译器的假设).

我对线程没有太多的经验,但是
thread\u done
不是原子的,所以可能您正在经历一个竞争条件?
我无法理解为什么这个调试行会对if条件函数是否如预期的那样是一个计时问题产生任何影响。该调试语句将需要时间来执行,改变所有事情的时间安排。谢谢你的评论,@Chipster。我认为这可能是一个竞争条件,特别是因为我以前在这段代码中犯过几次这个错误。但这次似乎不应该是这样,因为它100%使用4个线程或注释,但100%失败
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 = 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) {
//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