1

我正在将一些 OpenMP 并行循环移植到 GCD 以在 iOS 上使用。我遇到了一个我不确定如何最好地建模的构造。

OpenMP 循环对共享状态块执行一些重要的操作,它为每个可能的 OpenMP 线程分配一个,然后在循环之后组合(实际上是减少)结果。像这样(简化):

const int max_threads = omp_get_max_threads();
state_block state[max_threads];

#pragma omp parallel for shared(state) 
for(unsigned int i = 0; i < some_count; i++) {
    // do some stuff
    update_state(state[omp_get_thread_num()]);
}

merge_state_data(state, max_threads);

GCD 没有提供一种方法来了解可能的最大线程数是多少(是吗?)或您当前在哪个线程上,因此这种模式不起作用。状态块的大小很重要,并且迭代次数很大,因此为循环的每次迭代分配一个作为纯粹的最坏情况也是不合理的。

可以想象,我可以使用自定义调度源DISPATCH_SOURCE_TYPE_DATA_ADD来进行状态更新,但如果我这样原子化它,将需要数千个源,这似乎是错误的。

有什么我缺少的东西,无论是 GCD 还是这里的设计?

谢谢。

4

1 回答 1

1

您可以使用 POSIX 线程 API 函数pthread_setspecific()pthread_getspecific()在 iOS 上设置特定于线程的键,该键指向一个临时state_block对象,并稍后在当前执行的块中检索它。Apple 的并发编程指南不建议使用pthread_getspecific(),因为它可能会在不同的块运行中返回不同的值,但在您的情况下这是完全可以接受的(毕竟,这是您正在寻找的功能)。

由于您没有事先访问池的权限,因此您必须按需分配状态块:

  • 用于pthread_getspecific()获取state_block当前线程中的指针;
  • 如果未设置特定值,则分配一个新值state_block并将其分配给键的值,使用pthread_setspecific();
  • 用那个计算state_block

这可能会导致清理工作出现问题,例如考虑在所有任务执行后如何处理状态块。您可能希望使用指针共享表并将表中的唯一索引设置为线程特定值或类似值。您可以使用锁来序列化对索引值的访问——这是可以接受的,因为它只会在池中的每个线程中执行一次。

当然,这种方式依赖于 GCD 使用一个固定的线程池来实现它的并发队列。

于 2012-12-11T09:37:20.700 回答