【问题标题】:How to rewrite GCD code as POSIX in C如何在 C 中将 GCD 代码重写为 POSIX
【发布时间】:2016-04-30 08:15:10
【问题描述】:

这个问题是一个问题的后续,这个问题恰好比我最初想象的要复杂。在我正在编写的程序中,主线程负责 GUI 驱动的数据更新,生产者线程(具有多个子线程,因为生产者任务“令人尴尬地并行”)写入循环缓冲区,而真正的-time 消费者线程从中读取。最初的开发平台是 OSX/Darwin,但我想让代码更便携,与 UNIX 源代码兼容。一切都可以很容易地用 POSIX 编写,除了以下特定于 OSX 的 GCD 命令,我无法估计 POSIX 等效项(如果有)。它启动生产者线程,其子线程以编程方式从该线程启动,具体取决于可用逻辑 CPU 内核的数量:

void dproducer (bool on, int cpuNum, uData* data)
{
    if (on == true)
    {
    data->state = starting;
         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            producerSum(on, cpuNum, data);
        });
    }
return;
}

这是程序的框图:

为清楚起见,我还添加了 producerSum 代码。这是一个无限循环,其执行可以等待消费者线程完成工作,也可以通过更改具有全局范围的 data->state 来中断:

void producerSum(bool on, int cpuNum, uData* data)
{
int rc;
pthread_t threads[cpuNum]; //subthreads
tData thread_args[cpuNum];
void* resulT;
static float frames  [4096];

while(on){
    memset(frames,  0, 4096*sizeof(float));
   if( (fbuffW  = (float**)calloc(cpuNum + 1, sizeof(float*)))!= NULL)
      for (int i=0; i<cpuNum; ++i){
        fbuffW[i] = (float*)calloc(data->frames, sizeof(float));
        thread_args[i].tid = i;           //ord. number of thread
        thread_args[i].cpuCount = cpuNum; //counter increment step
        thread_args[i].data = data;
        rc = pthread_create(&threads[i], NULL, producerTN, (void *) &thread_args[i]);
        if(rc != 0)printf("rc = %s\n",strerror(rc));
      }        
    for (int i=0; i<cpuNum; ++i) rc = pthread_join(threads[i], &resulT);
    //each subthread writes to fbuffW[i] and results get summed
    for(UInt32 samp = 0; samp < data->frames; samp++)
        for(int i = 0; i < cpuNum; i++)
            frames[samp] += fbuffW[i][samp];

    switch (data->state) { ... } //graceful interruption, resuming and termination mechanism

    { … } //simple code for copying frames[] to the circular buffer

    pthread_cond_wait (&cond, &mutex);//wait for the real-time consumer

    for(int i = 0; i < cpuNum; i++) free(fbuffW[i]); free(fbuffW);
} //end while(on)    
return;
}

生产者线程内部的同步正在由 pthread_create( )pthread_join( ) 成功处理,而生产者和消费者线程之间的必要协调正在由 pthread_mutex_t 变量和 pthread_cond_t 变量成功处理>(带有相应的锁定、解锁、广播和等待命令)。 uData 是程序定义的结构(或类实例)。任何观察方向都会有所帮助。

感谢您阅读这篇文章!

【问题讨论】:

  • 请注意,libdispatch(即 GCD)是开源的,目前有大量工作来确保它可移植到所有支持 Swift 的平台(尤其是 Linux)。如果您的需求不是即时的,并且您只是试图转向更可移植的代码,那么您最好遵循该项目而不是重新实现所有内容。 github.com/apple/swift-corelibs-libdispatch 这可能比重新实现你已经工作的代码要好得多。
  • 这篇文章可能有用:newosxbook.com/articles/GCD.html
  • 谢谢,这对于 Linux 和 Swift 以及开源来说是一个非常好的消息,因为当不需要自定义线程和线程池时,GCD 真的很棒。然而,我更喜欢 远离 Swift 和 libdispatch,而宁愿留在主题上。我不必重新实现所有内容,只需一个命令,因为其他所有内容在 POSIX 中都可以正常运行。 “一切”不超过 500 行代码。谢谢,我知道newosxbook.com/articles/GCD.html。

标签: c multithreading macos unix posix


【解决方案1】:

调度队列就像它听起来的样子:一个队列,就像在标准的 FIFO 列表数据结构中一样。它拥有任务。这些任务可以通过代码中的 Objective-C 块或函数指针和上下文指针值来表示。如果您的目标是跨平台兼容性,您可能需要避免使用 Blocks。事实上,由于您只调度一个任务,您的任务可以只封装参数(oncpuNumdata)而不是代码(对 producerSum() 的调用)。

队列由线程池中的线程提供服务。 GCD 管理线程和池。至少在 OS X 上,它与 OS 集成,因此池的大小由整体系统负载控制,您将无法以跨平台的方式重现。

调度队列上的操作是线程安全的。这包括向它们添加任务以及工作线程从中删除任务。

您将不得不实现所有这些。这绝对是可能的,但会很麻烦。在许多方面,队列和线程池构成了生产者-消费者架构。基本上,您基于 GCD 的解决方案有点作弊,因为您只是使用了生产者-消费者 API 来实现您的生产者-消费者设计。现在,您将不得不在没有拐杖的情况下真正实现生产者-消费者设计。

基本上没有比你已经在使用的线程创建和 POSIX 条件变量更多的东西了。

dispatch_async() 基本上只是锁定任务队列的互斥体,将任务添加到队列中,发出条件变量信号,然后解锁互斥体。每个工作线程将只等待条件变量,当它唤醒时,锁定互斥锁,如果有任务从队列中弹出一个任务,解锁互斥锁,如果有一个任务则运行任务。您可能还需要一种机制来通知工作线程是时候正常终止了。

【讨论】:

  • 感谢您接受我的问题并接受我问这个问题是有原因的。我也一直觉得我与 GCD 打交道是一个快速的解决方法,只是在不知道自己在做什么的情况下做了一些很棒的事情而作弊。 work 是“令人尴尬的并行”,并且 2-24 个子线程是克隆:具有计数器偏移的积分器。否则,协调它们将毫无意义,因为它们不是独立的。我已将 producerSum 代码添加到问题中。我所需要的只是学习如何摆脱从主线程“生成”队列的“块”。
  • 队列未生成。所有dispatch_async() 都将任务放在列表中。正如我所说,有一个自动线程池为列表中的任务提供服务。如果您一直认为 dispatch_async() 只是“在单独的线程中运行”,而不是真正依赖队列的列表性质或 GCD 的线程池管理,那么您可以将其替换为 pthread_create()。跨度>
  • 谢谢。我目前正在研究 8 核和 16 核机器。根据您的建议,在dproducer() 中编写常规pthread_create,我稍微重写了producerSum() 调用以使其符合pthread。看起来无耻地简单,并且到目前为止通过了测试 - 我仍然需要更多时间来在实际程序中实现它。顺便说一句,是否有一篇文献可以让我了解更多关于在处理实时线程时编写可移植 UNIX 调度队列的信息,您可以推荐吗?
  • 抱歉,我不知道有任何类似的文献。
猜你喜欢
  • 2012-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-15
  • 2010-12-08
  • 2017-05-14
  • 2015-07-05
相关资源
最近更新 更多