iOS 中的操作同步挑战
Operation synchronisation challenge in iOS
我有 3 个操作:A
、B
、C
。
A
,B
可以并发处理
- 如果
C
运行,A
和 B
应该等待
- 如果
A
或 B
运行 C
应该等待
我会用调度组和信号量来解决:
public var dgLoadMain = dispatch_group_create()
public var semaLoadMain = dispatch_semaphore_create(1)
A
、B
看起来像这样:
dispatch_group_enter(dgLoadMain)
dispatch_semaphore_wait(semaLoadMain, DISPATCH_TIME_FOREVER)
dispatch_semaphore_signal(semaLoadMain) //maybe odd, but right after wait, it signals, it just check wether C is in critical section, if not, release semaphore, and let other B or A continue too
//..
dispatch_group_leave(dgLoadMain)
C
看起来像这样:
dispatch_group_wait(dgLoadMain, DISPATCH_TIME_FOREVER)
dispatch_semaphore_wait(semaLoadMain, DISPATCH_TIME_FOREVER)
//..
dispatch_semaphore_signal(semaLoadMain)
你觉得可以吗?
您的解决方案可能有效,但对其正确性的推理很痛苦。我想出了我认为更清洁的解决方案。它使用 2 个信号量。它基本上将任务 A 和任务 B 结合起来,并将它们视为一个任务。然后它使用超时 属性 检查任务 A 或任务 B 之前是否完成并相应地向第一个信号量发出信号。这是代码:
let semaphore = dispatch_semaphore_create(1);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
let ABSema = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
print("A")
if !Bool(dispatch_semaphore_wait(ABSema, DISPATCH_TIME_NOW))
{
dispatch_semaphore_signal(ABSema)
}
else
{
dispatch_semaphore_signal(semaphore)
}
})
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
print("B")
if !Bool(dispatch_semaphore_wait(ABSema, DISPATCH_TIME_NOW))
{
dispatch_semaphore_signal(ABSema)
}
else
{
dispatch_semaphore_signal(semaphore)
}
})
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
print("C")
dispatch_semaphore_signal(semaphore)
})
dispatch_barrier_async
更复杂。看看这段代码。它是 Objective-C,但同样的概念在 Swift 上绝对适用。
#import <Foundation/Foundation.h>
void A()
{
NSLog(@"A begin");
sleep(1);
NSLog(@"A end");
}
void B()
{
NSLog(@"B begin");
sleep(1);
NSLog(@"B end");
}
void C()
{
NSLog(@"C begin");
sleep(1);
NSLog(@"C end");
}
int main()
{
dispatch_queue_t q = dispatch_queue_create("ABC", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t qA = dispatch_queue_create("A", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(qA, q);
dispatch_queue_t qB = dispatch_queue_create("B", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(qB, q);
dispatch_barrier_async(q, ^{C();});
dispatch_async(qA, ^{A();});
dispatch_async(qA, ^{A();});
dispatch_async(qB, ^{B();});
dispatch_barrier_async(q, ^{C();});
dispatch_async(qB, ^{B();});
dispatch_barrier_async(q, ^{C();});
dispatch_async(qA, ^{A();});
dispatch_main();
return 0;
}
结果。
C begin
C end
A begin
B begin
A end
B end
B begin
A begin
B end
A end
A begin
A end
C begin
C end
C begin
C end
我有 3 个操作:A
、B
、C
。
A
,B
可以并发处理- 如果
C
运行,A
和B
应该等待 - 如果
A
或B
运行C
应该等待
我会用调度组和信号量来解决:
public var dgLoadMain = dispatch_group_create()
public var semaLoadMain = dispatch_semaphore_create(1)
A
、B
看起来像这样:
dispatch_group_enter(dgLoadMain)
dispatch_semaphore_wait(semaLoadMain, DISPATCH_TIME_FOREVER)
dispatch_semaphore_signal(semaLoadMain) //maybe odd, but right after wait, it signals, it just check wether C is in critical section, if not, release semaphore, and let other B or A continue too
//..
dispatch_group_leave(dgLoadMain)
C
看起来像这样:
dispatch_group_wait(dgLoadMain, DISPATCH_TIME_FOREVER)
dispatch_semaphore_wait(semaLoadMain, DISPATCH_TIME_FOREVER)
//..
dispatch_semaphore_signal(semaLoadMain)
你觉得可以吗?
您的解决方案可能有效,但对其正确性的推理很痛苦。我想出了我认为更清洁的解决方案。它使用 2 个信号量。它基本上将任务 A 和任务 B 结合起来,并将它们视为一个任务。然后它使用超时 属性 检查任务 A 或任务 B 之前是否完成并相应地向第一个信号量发出信号。这是代码:
let semaphore = dispatch_semaphore_create(1);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
let ABSema = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
print("A")
if !Bool(dispatch_semaphore_wait(ABSema, DISPATCH_TIME_NOW))
{
dispatch_semaphore_signal(ABSema)
}
else
{
dispatch_semaphore_signal(semaphore)
}
})
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
print("B")
if !Bool(dispatch_semaphore_wait(ABSema, DISPATCH_TIME_NOW))
{
dispatch_semaphore_signal(ABSema)
}
else
{
dispatch_semaphore_signal(semaphore)
}
})
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
print("C")
dispatch_semaphore_signal(semaphore)
})
dispatch_barrier_async
更复杂。看看这段代码。它是 Objective-C,但同样的概念在 Swift 上绝对适用。
#import <Foundation/Foundation.h>
void A()
{
NSLog(@"A begin");
sleep(1);
NSLog(@"A end");
}
void B()
{
NSLog(@"B begin");
sleep(1);
NSLog(@"B end");
}
void C()
{
NSLog(@"C begin");
sleep(1);
NSLog(@"C end");
}
int main()
{
dispatch_queue_t q = dispatch_queue_create("ABC", DISPATCH_QUEUE_CONCURRENT);
dispatch_queue_t qA = dispatch_queue_create("A", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(qA, q);
dispatch_queue_t qB = dispatch_queue_create("B", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(qB, q);
dispatch_barrier_async(q, ^{C();});
dispatch_async(qA, ^{A();});
dispatch_async(qA, ^{A();});
dispatch_async(qB, ^{B();});
dispatch_barrier_async(q, ^{C();});
dispatch_async(qB, ^{B();});
dispatch_barrier_async(q, ^{C();});
dispatch_async(qA, ^{A();});
dispatch_main();
return 0;
}
结果。
C begin
C end
A begin
B begin
A end
B end
B begin
A begin
B end
A end
A begin
A end
C begin
C end
C begin
C end