【问题标题】:Possible ways of implementing a dynamic barrier in mulithreaded programs在多线程程序中实现动态屏障的可能方法
【发布时间】:2011-10-17 15:51:44
【问题描述】:

我在一篇论文中读到了这个......

因此,我们的工具只在线程执行时检查点 在已知的安全点:内核入口、内核出口或某些 在我们确定是安全的内核中的可中断睡眠。 启动多线程分叉的线程在 它一直等到所有其他线程都达到安全点。一旦所有 线程到达屏障,原始线程创建检查点, 然后让其他线程继续执行。

现在我的问题是,谁能猜出作者在谈论什么样的障碍。线程如何创建屏障并将屏障也动态插入其他线程?任何工作示例都将受到高度赞赏。

已编辑

请不要说使用pthread_barrier_wait,因为这不是问题所在。显然,作者有一个线程可以动态地将障碍插入其他线程。我想知道怎么做?

【问题讨论】:

  • 为什么不问作者,而不是猜测?
  • “显然 ... 线程动态地将屏障插入其他线程”。该段没有说这个,你是在推断它。问作者。奇怪的是他们确实使用了简单的pthread_barrier_wait。奥卡姆剃刀适用于此。
  • 这肯定是检查点/重启的内核空间实现吗?论文是免费提供的吗?也许实现已经挂钩到那些“安全点”,当有一个检查点正在进行时,就会跳障碍舞。
  • 您能否提供有关您引用的论文的更多信息,以便我们了解更多背景信息?这样我们就不必猜测了。一个链接将是理想的。
  • 是的迈克尔,论文的链接是这个... www.eecs.umich.edu/~nsatish/papers/ASPLOS-10-Respec.pdf

标签: c++ c linux pthreads


【解决方案1】:

您询问的论文似乎是"Respec: Efficient Online Multiprocessor Replay via Speculation and External Determinism"。论文提到:

我们修改了 Linux 内核来实现我们的技术。

因此,我们创建了一个新的 Linux 原语,称为多线程 fork,它创建一个子进程,其线程数与其父进程相同。

所以当报纸这么说的时候

Respec 仅在线程在已知安全点执行时检查点:内核进入、内核退出或我们确定为安全的内核中的某些可中断睡眠。启动多线程分叉的线程会创建一个屏障,等待所有其他线程到达安全点。一旦所有线程都到达屏障,原始线程创建检查点,然后让其他线程继续执行。

我假设他们对 Linux 内核所做的修改中的逻辑是,正在记录的进程中的线程在到达这些“安全点”之一时将“进入”屏障(我还假设只有当已经发布了一个“多线程分叉”来创建屏障)。由于这发生在内核中,因此实现屏障很容易——实际上并没有任何动态发生。修改后的内核在这些战略安全点实施了屏障。

我还没有真正阅读过这篇论文(只是略读了几句)。如果一个或多个线程正在执行长时间不需要进入内核的工作,我并不完全清楚会发生什么 - 系统似乎依赖于线程到达那些明确的安全点。所以线程不应该在 CPU 密集型循环中磨蹭太久(这对于绝大多数程序来说可能不是问题):

请注意,由于我们的屏障实现,一个 epoch 的实际执行时间可能比 epoch 间隔长;在所有线程都到达屏障之前,无法获取检查点。

【讨论】:

  • 由于量子过期计数作为内核入口,上下文切换肯定是,唯一不安全的点是内核模式下的长时间运行计算、不间断睡眠和某些类型的可中断睡眠。
  • @ninjali:我对这篇论文所描述的系统了解不够,可以肯定地说,但我认为由于量子到期而导致的上下文切换可能不是 检查点线程的安全时间。
  • 为什么不呢?纯用户空间计算不应该是检查点线程的不安全地方,我认为唯一有问题的地方是在内核空间中运行时。
  • @ninjali:你可能是对的。我当然需要做更多的研究/分析,而不是我迄今为止所做的小事来证明你说的是错误的(如果它甚至是错误的)。我真的无法为我的评论辩护——这比断言更像是一种不安的感觉......另一方面,如果我正在实施这个检查点工具,我必须做更多的分析才能对依赖感到舒服关于你所说的。但这当然可能只是消除我的无知的问题。
【解决方案2】:

考虑到您的问题被标记为 linux 和 pthreads,我只能想象它指的是 pthread 障碍:

这是一个例子:

#include <pthread.h>
#include <stdio.h>

pthread_barrier_t bar;
pthread_t  th;

void* function(void*)
{  
    printf("Second thread before the barrier\n");
    pthread_barrier_wait(&bar);
    printf("Second thread after the barrier\n");
    return NULL;
}

int main()
{
    printf("Main thread is beginning\n");
    pthread_barrier_init(&bar, NULL, 2);
    pthread_create(&th, NULL, function, NULL); 
    pthread_barrier_wait(&bar);
    printf("Main thread has passed the barrier\n");
    pthread_join(&th,NULL);
    pthread_barrier_destroy(&bar);
    return 0;
}

【讨论】:

  • 在主线程中写“主线程已完成”,当它还没有完成时,会产生误导。
  • 这样使用pthread_create()真的安全吗?从技术上讲,您应该将 function 声明为 void*function(void*) 以符合要求。
  • @Tomalak:从技术上讲,在主线程完成之前不可能在主线程中写“主线程已经完成”......
  • @André:嗯?这根本不是不可能的。 OP做到了。不可能在不向阅读程序输出的人撒谎的情况下做到这一点。 :)
  • @André 你可以向atexit 注册一个函数并在那里执行,技术上应该在 main 完成后执行......
【解决方案3】:

障碍是fairly standard synchronization primitive

基本来说,进入屏障后,每个线程都会被阻塞,直到所有相关线程都到达屏障,然后全部释放。

我知道您问的是 C/C++,但请查看 Java 的 CyclicBarrier,因为那里对这个概念进行了很好的解释。

既然您询问的是 pthread,请查看 pthread_barrier_init 等。

编辑

但是在这种情况下,一个线程看似动态地插入了屏障 其他线程。怎么样?

如果没有某种背景(例如您正在阅读的论文),很难回答这个问题。

您引用的摘录给人的印象是这是对某些低级工具的描述,该工具要么插入在某些事件上执行的钩子(可能在相关线程的上下文中),要么确实在内核中运行模式。不管怎样,难怪它能做到它所说的那样。

在我看来,没有人在谈论用户线程动态地将障碍插入另一个用户线程。

希望我对上下文的猜测不会太远。

【讨论】:

  • 我知道 pthread_barrier_wait 等等!我在问如何在运行时创建屏障。 pthread_barrier_wait 在您知道放置屏障的位置时使用。但在这种情况下,一个线程似乎会在其他线程中动态插入屏障。怎么样?
  • @MetallicPriest:我已经用我的想法更新了答案。如果我离题了,请提供更多上下文。
【解决方案4】:

简单:使用 pthread_barrier_wait pthread API 调用。

详见手册页:http://linux.die.net/man/3/pthread_barrier_wait

【讨论】:

  • 我知道 pthread_barrier_wait,但我的问题是如何创建动态屏障。
【解决方案5】:

操作系统线程屏障只不过是内存中的某种状态。如果您可以在线程之间共享该状态(通过正确初始化线程),那么线程可以使用该屏障。

基本上是主线程做的:

CreateAllThreads(&barrier);
StartAllThreads();
EnterBarrier(&barrier);

所有其他线程都这样做:

RuntimeInitialize();
EnterBarrier(&barrier);

以上只是一个非常粗略的伪代码,仅供说明之用。

【讨论】:

    猜你喜欢
    • 2011-12-28
    • 2014-12-01
    • 2016-12-24
    • 2012-03-28
    • 1970-01-01
    • 2014-08-04
    • 2010-12-22
    • 2021-07-23
    • 1970-01-01
    相关资源
    最近更新 更多