使用两个处理器组的 C 线程处理

Posted

技术标签:

【中文标题】使用两个处理器组的 C 线程处理【英文标题】:C thread handling with two processor groups 【发布时间】:2020-04-28 11:43:38 【问题描述】:

我有一台装有 AMD Threadripper 3990x 的新 PC,它有 64 个内核和 128 个线程。

现在 Windows 10 只能在一个处理器组中处理 64 个内核。所以现在 Windows 制作了两个处理器组。

我编写了创建 N 个进程的软件。我检查如下有多少进程存在:

SYSTEM_INFO sysi;
GetSystemInfo(&sysi);
klas->thread_maxcore = min(sysi.dwNumberOfProcessors, MAX_THREADS);
klas->thread_max = klas->thread_maxcore;

如何调整我的代码以使用所有 128 个线程?使用我当前的代码,我一次只能运行 64 个进程,因此只能使用一个处理器组。

【问题讨论】:

您有什么特定版本/类型的Windows 10?它们在您的处理器上的表现各不相同。 (正如下面发布的链接中所指出的那样。) 我用w10专业版 考虑使用最近的Linux distribution。他们的 NUMA 支持在您的新 PC 上可能会更好。 C11 或 C++14 中的代码具有更好的平台中立多线程 【参考方案1】:

如何调整我的代码以使用所有 128 个线程

简短的回答是让您的软件了解处理器组,或者强制您的配置只有一个处理器组。

正如您所指出的,Windows 默认情况下,当看到超过 64 个线程时,会将它们分成处理器组。这可能就是您看到的线程数似乎较少的原因。虽然线程数少于您的预期,但它可能仅代表系统总线程数的一部分。

同时多线程有一个设置,默认情况下,在 Windows 10 中,此设置已打开。对于您的 64 核处理器,当启用同时多线程时,系统将显示 128 个线程,但这些线程分为两组。这种默认的 Windows 行为可能是阻止您查看(可见)所有线程的原因。关于您的具体要求我如何调整我的代码以使用所有 128 个线程

...当程序在组内运行时,除非是处理器 组感知,那么它只能访问同一组中的其他线程...

因此,答案是让您了解软件处理器组,或者通过禁用同时多线程进行设置以将所有内核放入单个处理器组,从而允许您的软件生成所有 128 个线程。 下面的链接中更详细地介绍了这两个选项的方法和权衡...

在此处阅读详细信息...The 64 core Threadripper 3990x CPU Review。

一些可能有助于让您的软件处理器组了解的链接:

C++11 threads, affinity, and hyper-threading

Thread pools and Windows processor groups

摘录改编 C++ 上一个链接的代码(由于这个问题被标记为C,因此将其视为伪代码

void DistributeThreads(void)

#if OS_WINDOWS_64
    //!!BUG!! need to skip this code for old windows versions
        int nNumGroups = GetActiveProcessorGroupCount();
    if ( nNumGroups > 1 )
    
        Log( "System has %d processor groups", nNumGroups );
        for(int i = 0; i < nNumGroups; i++ )
        
            Log(" group %d has %d processors", i, ( int ) GetMaximumProcessorCount( i ) );
        
        int nCurGroup = 0;
        int nNumRemaining = GetMaximumProcessorCount( nCurGroup );
        for( int i = 0; i < m_threads.size(); i ++ )
        
            auto hndl = m_threads[i].native_handle();
            GROUP_AFFINITY oldaffinity;
            if ( GetThreadGroupAffinity( hndl, &oldaffinity ) )
            
                //Log( "thread %d, old msk = %x, old grp = %llx", i, oldaffinity.Mask, oldaffinity.Group );
                GROUP_AFFINITY affinity;
                affinity = oldaffinity;
                if ( affinity.Group != nCurGroup )
                
                    affinity.Group = nCurGroup;
                    auto bSucc = SetThreadGroupAffinity( hndl, &affinity, nullptr );
                    if ( ! bSucc )
                    
                        Log( "failed to set gr aff err=%x", (int) GetLastError() );
                    
                    else
                    
                        //Log( "Set group for thread %d to %d", i, nCurGroup );
                    
                    --nNumRemaining;
                    if ( nNumRemaining == 0 )
                    
                        nCurGroup = min( nCurGroup + 1 , nNumGroups - 1 );
                        nNumRemaining = GetMaximumProcessorCount( nCurGroup );
                    
                
            
        
    
#endif
  

注意:在 MSDN 中搜索函数定义,例如:GetMaximumProcessorCount

【讨论】:

@JohnBollinger - 我已编辑,并相信内容现在与 OP 问题更相关。谢谢。 从未在 c 中使用过处理器组...您可以举个简单的例子吗? @Felix - 你看过链接中的示例代码吗?他们都对解释进行了足够详细的解释,并提供了代码来说明。 :)(请参阅答案中的编辑。)【参考方案2】:

该链接指向我的代码和文章。 我刚买了一个 128 核/256 线程和系统,正如你所料,Windows 处理器组意味着大多数程序只使用我的 1/4 内核。 包括visual c++并行STL算法:(。 该代码有效,但省去了所有麻烦,只需使用英特尔 TBB。 当你下载一个适用于 Windows 的线程应用程序并注意到它只使用了你系统的 25% 时,它真的很糟糕。 不要指望 msoft 对此做任何事情。我联系了 Visual c++ 团队,他们都关心我们为这个问题找借口。

【讨论】:

以上是关于使用两个处理器组的 C 线程处理的主要内容,如果未能解决你的问题,请参考以下文章

C多线程编程信号处理

线程之间的信号处理

13.7 线程组和为处理异常

13.7 线程组和为处理异常

使用委托进行跨线程处理的 C# 问题

在多线程 C++11 程序中未处理异常时会发生啥?