A
dispatch semaphore(信号量) is
useful if you need a concurrency control for a small
portion(部分) of the source code that has
smaller granularity(颗粒度) than
a serial dispatch
queue or dispatch_barrier_async function.
If data are updated concurrently, inconsistent(不一致的) data might
occur or the application might crash. You can avoid that by using a serial
dispatch queue or the dispatch_barrier_async function. But sometimes concurrency
control has to be done in smaller granularity.
(其实iOS的dispatch
semaphore和Windows系统的Semaphore的作用是一样的,都是用来作线程同步或者说资源的互斥访问的。当然在Windows系统下,除了Semaphore之外,CriticalSection、Event、Mutex也可以完成此功能。)
Let’s see an example to show how to add all the data to an
NSMutableArray when the order is unimportant.
1 2 3 4 5 6 7 8 9 10 |
dispatch_queue_t queue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0); NSMutableArray*array=[[NSMutableArrayalloc] init]; for(inti=0;i<100000;++i){ dispatch_async(queue,^{ [array }); } |
But, because the NSMutableArray class
doesn’t support multithreading, when the object is updated from many threads, it
will be corrupted(损坏). The
application probably crashes because of a memory-related problem. This is a race
condition(竞态[争]条件). We can use a dispatch semaphore in this case.
A dispatch semaphore is a semaphore with a counter. When
the counter is zero, the execution waits. When the counter is more than zero, it
keeps going after it decrements the counter.
The dispatch_semaphore_create function
creats a dispatch
semaphore.(相当于Windows系统的CreateSemaphore)
1 |
dispatch_semaphore_t semaphore=dispatch_semaphore_create(1); |
The argument is an initial value of the counter. As its name includes
“create”, you have to release it with the dispatch_release function. You can
have ownership by calling the dispatch_retain function as well.
1 |
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER); |
A dispatch_semaphore_wait function waits until
the counter of the dispatch semaphore becomes one and more. When
the counter is one and more, or the counter becomes one and more while it is
waiting, it decreases the counter and returns from the dispatch_semaphore_wait
function. The second argument specifies how long it waits in dispatch_time_t
type. In this example, it waits forever. The return value is the same as that of
the dispatch_group_wait function.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
dispatch_time_t time=dispatch_time(DISPATCH_TIME_NOW,1ull*NSEC_PER_SEC); longresult=dispatch_semaphore_wait(semaphore,time); if(result==0){ //The counter of //Or it became //The counter is //Here, you can }else{ //Because the //it has waited } |
When a dispatch_semaphore_wait function returns zero, a task that needs a
concurrency control can be executed safely. After finish the task,
you have to call
thedispatch_semaphore_signal(相当于Windows系统的ReleaseSemaphore) function
to increase the counter of the dispatch semaphore by one.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
dispatch_queue_t queue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0); //Set the initial //to //NSMutableArray dispatch_semaphore_t semaphore=dispatch_semaphore_create(1); NSMutableArray*array=[[NSMutableArrayalloc] init]; for(inti=0;i<100000;++i){ dispatch_async(queue,^{ dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER); //The counter of the dispatch semaphore is always zero //Because only one thread can access the object of the //at the same time, you can update the object [array //you have to call the dispatch_semaphore_signal //to increase the counter of the dispatch //If some threads are waiting for the //the first thread will be started. dispatch_semaphore_signal(semaphore); }); } //Originally, //you have to release the dispatch semaphore. //dispatch_release(semaphore); |
整理自《Multithreading and Memory Management for iOS and OS X》