c - 锁定 OMP 区域

标签 c multithreading locking openmp

我正在尝试在我的应用程序中检测一些函数,看看它们需要多长时间。我使用链接列表将所有时间记录在内存中。

在此过程中,我引入了一个全局变量来跟踪列表的末尾。当我输入新的计时区域时,我会在列表末尾插入一条新记录。相当简单的东西。

但是,我想要跟踪的一些函数是在 OpenMP 区域中调用的。这意味着它们可能会被并行调用多次。这就是我困惑的地方。

如果这是使用普通的 Pthreads,我只需将对全局变量的访问包装在互斥体中,然后就到此为止了。但是,我不确定:此策略是否仍适用于 OpenMP 区域中调用的函数?比如,他们会尊重锁吗?

例如(不会编译,但我认为明白了):

Record *head;
Record *tail;

void start_timing(char *name) {
    Record *r = create_record(name);
    tail->next_record = r;
    tail = r;
    return r;
}

int foo(void) {
   Record r = start_timing("foo");
   //Do something...
   stop_timing(r);
}

int main(void) {
   Record r = start_timing("main");
   //Do something...
   #pragma omp parallel for...
   for (int i = 0; i < 42; i++) {
       foo();
   }
   //Do some more...
   stop_timing(r);
}

然后我将更新为:

void start_timing(char *name) {
    Record *r = create_record(name);

    acquire_mutex_on_tail();
    tail->next_record = r;
    tail = r;
    release_mutex_on_tail();

    return r;
}

(如果有一个明显的答案,我深表歉意 - 我对 OpenMP 框架和多线程总体来说相对缺乏经验。)

最佳答案

惯用的互斥解决方案是使用 OpenMP 锁:

omp_set_lock(&taillock)
tail->next_record = r;
tail = r;
omp_unset_lock(&taillock)

某处:

omp_lock_t taillock;
omp_init_lock(&taillock);

...

omp_destroy_lock(&taillock);

简单的 OpenMP 解决方案:

void start_timing(char *name) {
    Record *r = create_record(name);
    #pragma omp critical
    {
        tail->next_record = r;
        tail = r;
    }
    return r;
}

这会创建一个绑定(bind)到源代码行的隐式全局锁。有关一些详细讨论,请参阅 this question 的答案.

出于实际目的,使用 Pthread 锁也可以,至少对于 OpenMP 基于 Pthread 的场景来说是这样。

警告一句话

在性能测量代码中使用锁是危险的。内存分配也是如此,这通常也意味着使用锁。这意味着 start_time 具有显着的成本,并且随着线程数量的增加,性能甚至会变得更差。这甚至没有考虑由于一个线程分配一 block 内存(记录)然后另一个线程修改它(尾指针)而导致的缓存失效。

现在,如果您测量的部分需要几秒钟,这可能没问题,但当您的部分只有数百个周期时,就会导致巨大的开销和扰动。

要创建可扩展的性能跟踪工具,您必须以更大的 block 预先分配线程本地内存,并让每个线程仅写入其本地部分。

您还可以选择使用一些现有的测量基础设施,例如 Score-P .

开销和扰动

首先,区分两者(相关概念)。 开销是您花费的额外时间,而扰动是指对您测量的内容的影响(即您现在测量的东西与没有测量时发生的情况不同)。大量的开销是不受欢迎的,但扰动会更糟。

是的,您可以通过在昂贵的测量运行时间期间暂停计时器来避免一些干扰(开销仍然存在)。然而,在多线程上下文中这仍然是一个很大的问题。

  • 减慢一个线程的进度,可能会导致其他线程等待它,例如在隐式障碍期间。您如何归因该线程和其他传递性后续线程的等待时间?
  • 内存分配通常是锁定的 - 因此,如果您在测量运行时分配内存,则会减慢依赖于内存分配的其他线程的速度。您可以尝试使用内存池来缓解,但我首先会避免使用链表。

关于c - 锁定 OMP 区域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40956148/

相关文章:

c - 连接 int 和字符串时 sprintf 无法正常工作

objective-c - 使用 BLWebSocketsServer 写入 websocket

c - 将值分类到适当的组中 : Counter Arrays

python - selenium python 中的多线程

.net - SempahoreSlim 作为异步代码中的锁的正确用法是什么?

java - ReentrantReadWriteLock的 "non-fair"模式怎么理解?

postgresql - 锁定行直到下一次选择 postgres

c - 为什么我的浮点值不能正确打印?

python - 如何在 python/numpy 中自动化 BLAS 的环境变量相关基准测试?

python-3.x - 如何同时运行两个脚本