我执行的任务非常繁重,我不想阻止主线程。所以我为它启动了一个单独的并发队列。该任务可以有4个实例。
-(dispatch_queue_t)getConcurrentQueue
{
if(concurrentQueue == nil)
{
concurrentQueue = dispatch_queue_create("com.myself.HeavyTask", DISPATCH_QUEUE_CONCURRENT);
}
return concurrentQueue;
}
现在开始我的繁重任务 -
-(void)beginTask
{
//.....
//.....
__weak typeof(self) weakSelf = self;
dispatch_queue_t queue = [self getConcurrentQueue];
dispatch_async(queue, ^{
[weakSelf heavyTask];
});
}
现在方法heavyTask就是这样 -
-(void)heavyTask
{
//...
dispatch_sync(dispatch_get_current_queue(), ^{
// Initialising code for heavy task
// This is the critical section. Only one of the 4 concurrent threads can enter this at a time
}
//....
while(condition)
{
// Perform meat of the task
}
//...
dispatch_sync(dispatch_get_current_queue(), ^{
// Teardown code. Freeing memory etc.
// This is also a critical section.
}
//...
}
初始化代码和拆解代码使用一些非线程安全的第三方C方法。因此,使它们线程安全不是问题的范围。
现在我已将"initialising code"
和"teardown code"
放在 -
dispatch_sync(dispatch_get_current_queue(), ^{
}
我的代码崩溃,我收到错误消息,指出关键部分代码周围没有足够的线程锁定。
我认为dispatch_get_current_queue()
不安全,所以我将其替换为concurrentQueue
。我也尝试用dispatch_get_main_queue()
替换。代码仍然崩溃,抱怨线程锁定不足。
我知道使用GCD实现关键部分的理解存在问题。
任何人都可以清楚地告诉我如何使我的代码在这里正常工作吗?
附带问题 - 我可以在这里使用@synchronized { }
块吗?
答案 0 :(得分:2)
您的代码存在很多问题,包括不遵守命名约定。
基本上,如果你想相互执行相同的并发任务,请使用全局并发队列来执行这些任务。
如果要同时从这些任务(或其他地方)访问共享资源,请定义一个专用队列,例如“sync_queue”,您可以在其中专门访问这些资源。这个“sync_queue”执行你的“关键部分”。
“sync_queue”可以是串行或并发的。
如果您使用串行队列,请使用dispatch_async(sync_queue, block)
进行写访问,使用dispatch_sync(sync_queue, block)
进行读访问共享资源。
如果您使用并发队列,请使用dispatch_barrier_async(sync_queue, block)
进行写访问,使用dispatch_barrier_sync(sync_queue, block)
进行读访问共享资源。
示例:
// Read access using a serial sync_queue:
...
__block int counter;
dispatch_sync(sync_queue, ^{
counter = _counter;
});
// Write access using a serial sync_queue:
...
dispatch_async(sync_queue, ^{
_counter = counter;
});
// Read access using a concurrent sync_queue:
...
__block int counter;
dispatch_barrier_sync(sync_queue, ^{
counter = _counter;
});
// Write access using a concurrent sync_queue:
...
dispatch_barrier_async(sync_queue, ^{
_counter = counter;
});
“繁重任务”的示例:
-(void)heavyTask
{
dispatch_barrier_async(sync_queue, ^{
// Initialize heavy task
...
// Continue with the task:
dispatch_async(dispatch_get_global_queue(0,0), ^{
BOOL condition = YES; // condition must be local to the block (it's not a shared resource!)
while(condition)
{
// Perform meat of the task
condition = ...;
}
dispatch_barrier_async(sync_queue, ^{
// Teardown code. Freeing memory etc.
// This is also a critical section.
...
}
});
}
}
答案 1 :(得分:0)
您将其称为“getSerialQueue”,但实际上您正在其中创建“并发”队列。尝试用getSerialQueue中的DISPATCH_QUEUE_SERIAL代替DISPATCH_QUEUE_CONCURRENT修复它。
请记住:
dispatch_sync表示:我将在此处等待此块完成
dispatch_async表示:我不会等待
这与并发或串行无关。如果并发队列中的两个任务调用dispatch_sync(block),则'block'将同时执行。
希望这有帮助。