IOS Operations Synchronization Task
I have 3 steps: A
, B
, C
.
-
A
,B
can be processed simultaneously - If it
C
worksA
andB
must wait - if
A
orB
worksC
must wait
I would solve it with a dispatch group and a semaphore:
public var dgLoadMain = dispatch_group_create()
public var semaLoadMain = dispatch_semaphore_create(1)
A
, B
Will look like this:
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
will look like this:
dispatch_group_wait(dgLoadMain, DISPATCH_TIME_FOREVER)
dispatch_semaphore_wait(semaLoadMain, DISPATCH_TIME_FOREVER)
//..
dispatch_semaphore_signal(semaLoadMain)
Do you think everything is okay?
source to share
dispatch_barrier_async
more difficult. Take a look at this code. It's Objective-C, but the same concept works great in 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;
}
Result.
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
source to share
Your solution probably works, but reasoning about it was painful. I came up with what I thought was a cleaner solution. It uses 2 semaphores. It basically combines task A and task B and treats them as one task. And then it uses the timeout property to check if Task A or Task B has been executed previously and is passed to the first semaphore accordingly. Here's the code:
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)
})
source to share