2011-02-15 27 views
0

我有3个线程(除了主线程)。线程读取,处理和写入。他们每个人都会对一些缓冲区执行此操作,这些缓冲区会循环使用并重新使用。它以这种方式设置的原因是程序可以在其中一个正在运行时继续执行其他任务。因此,例如,当程序写入磁盘时,它可以同时读取更多数据。使用NSConditionLock同步3个线程共享缓冲区。这很难

问题是我需要同步所有这些,以便处理线程不会尝试处理尚未填充新数据的缓冲区。否则,处理步骤可能会处理其中一个缓冲区中的剩余数据。

读取线程将数据读入缓冲区,然后将缓冲区标记为数组中的“新数据”。因此,它的工作原理是这样的:

//set up in main thread 
NSConditionLock *readlock = [[NSConditionLock alloc] initWithCondition:0]; 

//set up lock in thread 
[readlock lockWhenCondition:buffer_new[current_buf]]; 

//copy data to buffer 
memcpy(buffer[current_buf],source_data,data_length); 

//mark buffer as new (this is reset to 0 once the data is processed) 
buffer_new[current_buf] = 1; 

//unlock 
[readlock unlockWithCondition:0]; 

我用buffer_new [current_buf]作为条件变量NSConditionLock。如果缓冲区未被标记为新的,那么该线程将被锁定,等待前一个线程写入新数据。这部分似乎工作正常。

主要问题是我需要同步这两个方向。如果由于某种原因读取线程花费时间过长,并且处理线程已经完成处理所有缓冲区,则处理线程需要等待,反之亦然。

我不确定NSConditionLock是做到这一点的适当方法。

+1

是的。线程很难。 – bbum

回答

2

我会打开它的头。正如你所说,线程很难,线程的多路同步更困难。基于队列的并发性通常更加自然。

定义三个队列;读队列,写队列和处理队列。然后使用一条规则,规定没有缓冲区应该在时间在多于一个队列中入队。

也就是说,一个缓冲区可以被排队到读队列上,一旦读完,排队到处理队列中,并且一旦完成处理,排队到写队列中。

你可以使用缓冲区的堆栈,如果你想要,但通常情况下,相对于加工的成本分摊的成本相当便宜,因此,排队换读也可以做分配,同时离队,once-书面可以做免费的。

这对于使用GCD进行编码非常简单。请注意,如果您确实需要并行性,那么您的各种队列实际上只会被限制,使用信号量(可能是共享的)将队列排入全局并发队列。

还要注意,这个设计比你当前使用的有一个明显的优势,它不使用锁。作为队列管理的一部分,唯一的锁隐藏在GCD API的下方,但是这对您的代码是有效的。

+1

我想保持代码尽可能便携,因此使用NSLocks/pthreads。我最终做的是使用NSConditionLock和NSCondition的组合。经过很多测试,似乎工作正常。使用直线C移植到Linux可能会有点棘手,但至少我知道这是可能的,因为Cocoa的NSLocks在内部使用pthread。 – Synthetix

1

你见过那么Apple Concurrency Programming Guide ?

它建议移动从线程和锁并发模型走几个最好的方法。例如,使用“操作队列”不仅可以减少和简化代码,加快开发速度并提高性能。

有时你需要使用线程,并且你已经有了正确的想法。您将需要不断添加锁,并且每个锁都会呈指数级增长,直到您无法理解您自己的代码。然后你可以开始在随机的地方添加锁。然后你被搞砸了。

阅读并发指南,然后遵循bbum的建议。

+1

* ...你无法理解你自己的代码。然后你可以开始在随机的地方添加锁。那你就搞砸了。*智慧的话,那。 – bbum