首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用原子内建的纺丝屏障

用原子内建的纺丝屏障
EN

Stack Overflow用户
提问于 2015-11-08 20:29:06
回答 1查看 1.5K关注 0票数 1

我正在尝试使用atomics,特别是__sync_fetch_and_add来实现一个旋转线程屏障。https://gcc.gnu.org/onlinedocs/gcc-4.4.5/gcc/Atomic-Builtins.html

我基本上想要一个替代线程屏障的方法。我在一个可以并行运行大约100个线程的系统上使用Ubuntu。

代码语言:javascript
复制
int bar = 0;                      //global variable
 int P = MAX_THREADS;              //number of threads

 __sync_fetch_and_add(&bar,1);     //each thread comes and adds atomically
 while(bar<P){}                    //threads spin until bar increments to P
 bar=0;                            //a thread sets bar=0 to be used in the next spinning barrier

这显然不起作用(线程可能设置bar=0,而另一个线程被困在无限时间循环中等等)。我在这里看到了一个实现:使用c++11 atomics编写一个(旋转的)线程屏障,但是它看起来太复杂了,我认为它的性能可能比线程屏障差。

该实现还将在内存层次结构中产生更多的通信量,这是因为bar的缓存线在线程之间进行ping连接。

对于如何利用这些原子指令制造一个简单的屏障,有什么想法吗?另外,通信最优方案也会有所帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-11-09 12:47:53

与其在线程的计数器上旋转,倒不如利用通过的障碍物的数量来旋转,这将只增加最后一个线程面对障碍物的数量。这样还可以减少内存缓存压力,因为旋转变量现在只通过单线程更新。

代码语言:javascript
复制
int P = MAX_THREADS;
int bar = 0; // Counter of threads, faced barrier.
volatile int passed = 0; // Number of barriers, passed by all threads.

void barrier_wait()
{
    int passed_old = passed; // Should be evaluated before incrementing *bar*!

    if(__sync_fetch_and_add(&bar,1) == (P - 1))
    {
        // The last thread, faced barrier.
        bar = 0;
        // *bar* should be reseted strictly before updating of barriers counter.
        __sync_synchronize(); 
        passed++; // Mark barrier as passed.
    }
    else
    {
        // Not the last thread. Wait others.
        while(passed == passed_old) {};
        // Need to synchronize cache with other threads, passed barrier.
        __sync_synchronize();
    }
}

注意,您需要使用volatile修饰符来旋转变量。

C++代码可能比C代码要快一些,因为它可以使用获取/释放内存屏障而不是完整的内存屏障,这是__sync函数唯一可用的屏障:

代码语言:javascript
复制
int P = MAX_THREADS;
std::atomic<int> bar = 0; // Counter of threads, faced barrier.
std::atomic<int> passed = 0; // Number of barriers, passed by all threads.

void barrier_wait()
{
    int passed_old = passed.load(std::memory_order_relaxed);

    if(bar.fetch_add(1) == (P - 1))
    {
        // The last thread, faced barrier.
        bar = 0;
        // Synchronize and store in one operation.
        passed.store(passed_old + 1, std::memory_order_release);
    }
    else
    {
        // Not the last thread. Wait others.
        while(passed.load(std::memory_order_relaxed) == passed_old) {};
        // Need to synchronize cache with other threads, passed barrier.
        std::atomic_thread_fence(std::memory_order_acquire);
    }
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33598686

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档