【问题标题】:Can MFC multithread program run in a parallel method?MFC多线程程序可以并行方式运行吗?
【发布时间】:2017-12-26 09:20:56
【问题描述】:

我想在 MFC 中使用多线程。我正在做一个小实验,看看程序是否以并行方式运行。我这样写了两个线程函数:

UINT CMFCApplication2Dlg::thread01(LPVOID pParam)
{
    clock_t t1, t2;
    t1 = clock();
    for (int i = 0; i < 300000; i++)
        cout << "thread01111111111" << endl;

    t2 = clock();
    cout << "clock is " << t2 - t1 << endl;
    return 0;
}

UINT CMFCApplication2Dlg::thread02(LPVOID pParam)
{
    clock_t t1, t2;
    t1 = clock();

    for (int i = 0; i < 300000; i++)
        cout << "thread02222222222" << endl;


    t2 = clock();
    cout << "clock is " << t2 - t1 << endl;
    return 0;
}

并调用它们并输出到控制台窗口:

AllocConsole();                     

    freopen("CONOUT$", "w+t", stdout);

    freopen("CONIN$", "r+t", stdin);  

    printf("Hello World!\n");         

    CWinThread *pThread01;
    CWinThread *pThread02;
    pThread01 = AfxBeginThread(thread01, this, 0, 0, 0, NULL);
    pThread02 = AfxBeginThread(thread02, this, 0, 0, 0, NULL);

同时运行两个线程时,计数为118020;单线程运行时,计数为60315;当以串行方式将两个循环放在同一个线程中时,我得到 102795。

我以前认为编译器可以优化多线程自动并行执行,但似乎单核多线程并发可以。它不会减少运行时间。我使用的 CPU 有 4 个内核。我应该怎么做才能在不同的核心并行运行线程以实现高性能?

【问题讨论】:

  • 这个问题没有意义。它遵循“多线程是答案,问题是什么?”图案。如果您想要更好的答案,您需要提出更好的问题(即编写更好的测试代码)。如果您已经知道答案,您只能提出更好的问题。
  • 对不起,我不能完全理解你的意思。如果你的意思是测试代码太糟糕,那可能是因为我没有接受过正式的 CS 培训。您可以直接参考我的代码中的不足。
  • 您的代码使用全局资源(大概是std::cout),当从多个线程访问时,它不保证输出顺序。因此,使用观察到的输出顺序作为逻辑推理的基础并不是很有用。您无法根据不可靠的输入推断出可靠的结果。你需要一本关于并发的好书,以及一本关于 CPU 架构的好书。另外,一本关于 MFC 的好书,如果你想使用 MFC。
  • 感谢您的指正。好吧,我不想深入研究 MFC,因为我听说它已经很老了。那么还有其他高效的 GUI 支持的多线程值得学习吗?答案是否引用了 MSDN 中的并发运行时好学?还是有其他建议?
  • 任何东西(包括MFC)都很好学,这样你就可以做出明智的决定。根据您听说某些技术已经过时而做出决定,这不是一个好的决定,只有靠运气才能做出正确的决定。

标签: c++ multithreading mfc


【解决方案1】:

两个线程都试图同时使用共享资源 (std::cout)。系统必须在某一时刻对输出进行序列化,因此大部分时间其中一个线程将等待另一个线程完成写入。这称为同步。当您使用线程来提高性能时,您希望尽可能减少同步所花费的时间,因为在此期间线程无法做有用的工作。

尝试用冗长的计算替换内部循环中的cout,并且只在最后使用cout来打印最终结果,因此编译器无法优化计算(没有cout它可以,因为计算不会产生明显的影响)。

另外,std::clock 缺乏分析精度。我建议改用std::chrono::high_resolution_clock,这通常在Windows 平台上使用QueryPerformanceCounter() 实现。这是您在 Windows 上可以获得的最佳效果。

试试这个:

INT CMFCApplication2Dlg::thread01(LPVOID pParam)
{
    using myclock = std::chrono::high_resolution_clock;
    auto t1 = myclock::now();

    std::int64_t first = 0, second = 1, result = 0;
    for( std::int64_t i = 0; i < 10000000; ++i )
    {
         result = first + second;
         first = second;
         second = result;
    }

    auto t2 = myclock::now();   
    std::chrono::duration<double> td = t2 - t1;  // duration in seconds

    std::cout << "result is " << result << '\n'
              << "clock is " << std::fixed << std::setprecision( 6 ) << td.count() << " s" << std::endl;

    return 0;
}

确保计算不要太简单,因为优化器非常聪明,例如可能会将您的 O(n) 算法变成 O(1)。它甚至可以在编译时完成整个计算,并且只在运行时分配一个常量。 为避免这种情况,您可以改为从cin 读取循环迭代次数。尽管在 MSVC 2017 上测试上述代码时,即使进行了全面优化,也没有必要这样做。

【讨论】:

  • 感谢您的细心解释。经过测试,我在两个线程和单个线程之间获得了相同的运行时间。我观察到运行时间会随着线程的增加而增加(不超过逻辑核心的数量)。我使用'SetThreadAffinityMask'强制线程在同一个核心上运行但失败,是因为系统自动分发吗?
【解决方案2】:

阅读并发运行时。它可以帮助您不头痛:https://msdn.microsoft.com/en-us/library/dd504870.aspx

【讨论】:

  • 这如何解决所提出的问题?
  • 并发运行时机制可以让多线程写起来更简单易用。这就是他想做的。
  • 假的。 OP 在问,为什么他们的多线程应用程序似乎没有并行运行多个线程。但是,确实如此,只是他们的测试是错误的,他们得出了错误的结论。切换到不同的多线程框架在这里无济于事。 -1 无用。而且错了。
猜你喜欢
  • 1970-01-01
  • 2010-12-04
  • 1970-01-01
  • 2016-01-28
  • 1970-01-01
  • 2013-06-24
  • 2014-09-17
  • 2016-11-25
相关资源
最近更新 更多