【发布时间】: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