C++ 上的多线程控制台应用程序挂起

Multithreaded console app on C++ is hanging

我编写了多线程控制台程序来并行计算。程序来自 PowerShell 运行。一般来说,它运行良好:主线程、输出线程和 7 个工作线程(8 个逻辑核心),CPU 使用率为 85%。但有时,例如当我使用笔记本电脑执行一些其他任务时:网上冲浪、在 MS Word 中进行简单工作,e.t.c,所有线程都停止,CPU 使用率为 0%。如果我按Ctrl+C,有结束线程的输出结果,程序正常连续工作。

同时创建和停止所有线程:

Started:  k =     1 N/mm, dzeta = 0.01
Started:  k =     1 N/mm, dzeta = 0.1
Started:  k =     1 N/mm, dzeta = 0.2
Started:  k =     1 N/mm, dzeta = 0.5
Started:  k =     1 N/mm, dzeta = 0.7
Started:  k =     1 N/mm, dzeta = 1
Started:  k =     2 N/mm, dzeta = 0.01
Started:  k =     2 N/mm, dzeta = 0.1
Finished: k =     1 N/mm, dzeta = 0.1, Last n_rot 29.2 krpm.
Finished: k =     1 N/mm, dzeta = 0.01, Last n_rot 29.6 krpm.
Finished: k =     1 N/mm, dzeta = 0.2, Last n_rot 29.4 krpm.
Finished: k =     2 N/mm, dzeta = 0.01, Last n_rot 29.7 krpm.
Finished: k =     1 N/mm, dzeta = 0.7, Last n_rot 29.5 krpm.
Finished: k =     1 N/mm, dzeta = 1, Last n_rot 29.6 krpm.
Finished: k =     1 N/mm, dzeta = 0.5, Last n_rot 29.4 krpm.
Started:  k =     2 N/mm, dzeta = 0.2
Started:  k =     2 N/mm, dzeta = 0.5
Started:  k =     2 N/mm, dzeta = 0.7
Started:  k =     2 N/mm, dzeta = 1
Started:  k =     3 N/mm, dzeta = 0.01
Started:  k =     3 N/mm, dzeta = 0.1
Started:  k =     3 N/mm, dzeta = 0.2

正常工作

Started:  k =     3 N/mm, dzeta = 0.2
Finished: k =     2 N/mm, dzeta = 0.2, Last n_rot 29.4 krpm.
Started:  k =     3 N/mm, dzeta = 0.5
Finished: k =     2 N/mm, dzeta = 1, Last n_rot 29.6 krpm.
Started:  k =     3 N/mm, dzeta = 0.7
Finished: k =     2 N/mm, dzeta = 0.5, Last n_rot 29.5 krpm.
Started:  k =     3 N/mm, dzeta = 1
Finished: k =     2 N/mm, dzeta = 0.7, Last n_rot 29.6 krpm.
Started:  k =     4 N/mm, dzeta = 0.01
Finished: k =     3 N/mm, dzeta = 0.01, Last n_rot 29.9 krpm.
Started:  k =     4 N/mm, dzeta = 0.1
Finished: k =     2 N/mm, dzeta = 0.1, Last n_rot 29.3 krpm.
Started:  k =     4 N/mm, dzeta = 0.2
Finished: k =     3 N/mm, dzeta = 0.1, Last n_rot 29.4 krpm.
Started:  k =     4 N/mm, dzeta = 0.5
Finished: k =     3 N/mm, dzeta = 0.2, Last n_rot 29.4 krpm.
Started:  k =     4 N/mm, dzeta = 0.7
Finished: k =     3 N/mm, dzeta = 0.5, Last n_rot 29.6 krpm.
Started:  k =     4 N/mm, dzeta = 1
Finished: k =     3 N/mm, dzeta = 1, Last n_rot 29.7 krpm.

很高兴知道为什么会结冰!

主线程

std::list<Answer> results;
AnswersContainerClass AnswersContainer;

int Max_Number_Threads = std::thread::hardware_concurrency() - 1;
std::atomic<int> Threads_counter = 0;
std::atomic<bool> end_flag = false;

std::future<bool> results_are_out = std::async(std::launch::async, multithread_results_output, &results, &AnswersContainer, &end_flag, &dzeta_test, &k_tests);

boost::posix_time::ptime begin_time(boost::posix_time::second_clock::local_time()); 

for (unsigned int i = N_k_first; i < N_k_last; i++) {
    for (unsigned int j = N_dzeta_first; j < N_dzeta_last; j++)
    {
        PointHousingEquationSystem *ODE_copy = new PointHousingEquationSystem(ODE);
        std::unique_ptr<StiffIntegratorT> stiffT = std::make_unique<StiffIntegratorT>(ODE_copy, ODE_copy->GetND(), y, x_begin, x_end);

        stiffT->SetMaxStepSize(max_step_size);
        stiffT->SetMaxNumberOfSteps(200'000);       

        ODE_copy->System->Bearing.set_dzeta_corp(dzeta_test[j]);
        ODE_copy->System->Bearing.set_k_corp_bearing(k_tests[i]);

        if (cout_flag)
        {
            stdcout_mutex.lock();
            std::cout << "Started:  k = " << std::setw(5) << k_tests[i] / 1000. << " N/mm, " << "dzeta = " << std::setprecision(3) << dzeta_test[j] << std::endl;
            stdcout_mutex.unlock();
        }

        while (Threads_counter >= Max_Number_Threads)
            std::this_thread::sleep_for(1000ms);

        AnswersContainer.flag.lock();
        AnswersContainer.Answers.push(std::async(std::launch::async, Background_Solver, i, j, ODE_copy, move(stiffT), &Threads_counter));
        AnswersContainer.flag.unlock();

        Threads_counter++;
    }
}

end_flag.store(true, std::memory_order::memory_order_relaxed);
results_are_out.get();

background_worker

Answer Background_Solver(unsigned int i, unsigned int j, PointHousingEquationSystem *ODE, std::unique_ptr<StiffIntegratorT> Integrator, std::atomic<int> *Threads_counter)
{
    bool showed = false;

    try 
    {
        Integrator->Integrate();
    }
    
    catch (std::runtime_error &e)
    {
        stdcout_mutex.lock();
        std::cout << "Finished: k = " << std::setw(5) << ODE->System->Bearing.get_k_corp_bearing() / 1000. << " N/mm, " << "dzeta = " << std::setprecision(3)
                  << ODE->System->Bearing.get_dzeta_corp() << ", Last n_rot " << ODE->System->Point.get_rotation_frequancy() << " krpm." << std::endl;
        stdcout_mutex.unlock();
        showed = true;
    }
    catch (...)
    {
        stdcout_mutex.lock();
        std::cout << "Caught an unknown exception" << std::endl;
        stdcout_mutex.unlock();
        (*Threads_counter)--;
        delete ODE;
        return Answer(i, j, -1.0);
    }

    if (!showed) {
        stdcout_mutex.lock();
        std::cout << "Finished: k = " << std::setw(5) << ODE->System->Bearing.get_k_corp_bearing() / 1000. << " N/mm, " << "dzeta = " << std::setprecision(3)
                  << ODE->System->Bearing.get_dzeta_corp() << ", Last n_rot " << ODE->System->Point.get_rotation_frequancy() << " krpm." << std::endl;
        stdcout_mutex.unlock();
    }

    (*Threads_counter)--;

    double rotation_frequancy = ODE->System->Point.get_rotation_frequancy();
    delete ODE;
    return Answer(i, j, rotation_frequancy);
}

multithread_output

bool multithread_results_output(std::list<Answer> *results, AnswersContainerClass *Answers, std::atomic<bool> *end_flag,
    std::vector<double> *dzeta_test, std::vector<double> *k_tests)
{
    std::ofstream output_file;
    output_file.open(output_filename);

    std::this_thread::sleep_for(1000ms);

    while (!(*end_flag) || !(Answers->Answers.empty()))
    {
        Answer ans = Answers->Answers.front().get();
        results->push_back(ans);
        
        if (ans.j == 0)
        {
            output_file << (*k_tests)[ans.i] << " " << ans.omega << " ";
        }
        else
        {
            if (ans.j < (N_dzeta_last - 1))
                output_file << ans.omega << " ";
            else
                output_file << ans.omega << std::endl;
        }

        Answers->flag.lock();
        Answers->Answers.pop();
        Answers->flag.unlock();

        std::this_thread::sleep_for(1000ms);
    }

    output_file.close();
    return true;
}

陈百强,说的对!如果我单击 PowerShell 并触发文本选择(见图),程序会堆叠在 std::cout 上并且似乎被冻结了。 Ctrl+C后,std::out释放,继续进行。

Cygwin Bash 没有这样的问题,我无法用 gdb 解决这个问题。