The use of locks between multiple threads in iOS development

Source: Internet
Author: User
Tags gcd

Why you need to use locks, of course, familiar with multi-threaded you, nature will not feel strange.

Did you use the lock mechanism well in the code? Do you know several ways to implement locks?

main.m

 1 int main (int argc, const char * argv[]) {2 @autoreleasepool {3//common usage; you will see thread 1 lock, thread 2 waits until thread 1 executes, and thread 2 executes 4 NSLog (@ "Use Nslock (normal lock; implemented Nslocking protocol) to implement lock"); 5 [Lockbynslock Executelock]; 6 7 NSLog (@ "use synchronized command to implement lock"); 8 [lockbysynchronized Executelock];         9 NSLog (@ "pthread_mutex_t with C language"); [Lockbypthreadmutext executelock];12 13         NSLog (@ "Use GCD dispatch_semaphore_t (semaphore) to achieve lock"); [Lockbydispatchsemaphoret executelock];15 16 17 Advanced usage NSLog (@ "uses nsrecursivelock (recursive lock; implemented nslocking protocol) to implement locks; can be used in recursive scenarios. If Nslock is used, a deadlock occurs "), [Lockbynsrecursivelock executelock];20 NSLog (@" Using nsconditionlock (conditional lock; implemented N Slocking protocol), which can be used in scenarios where a condition is required to perform a lock operation; [Lockbynsconditionlock executelock];23 NSLog (@ "Using NSDI Stributedlock (distributed locks; different lock types, which do not implement the Nslocking protocol) implement locks; It is based on the file system, automatically creates temporary files or folders for identification, and automatically cleans up temporary files or folders after execution finishes. , which can be used in scenarios in which multiple processes or multiple programs need to build mutually exclusive"); [Lockbynsdistributedlock Executelock]; There is no effect, the specific test should be thread 1 and thread 2 at the same time, that is, between multiple processes or multiple programs need to build mutually exclusive scenario}27 return 0;28}

Today, let's explore some of the different ways to implement locks in IOS, before we build a class for testing, assuming it's one of our shared resources, FirstMethod and Secondmethod are mutually exclusive, and the code is as follows:

1 #import "TestObj.h" 2  3 @implementation testobj 4  5-(void) FirstMethod {6     NSLog (@ "Execute%@", Nsstringfro Mselector (_cmd)); 7} 8  9-(void) Secondmethod {     NSLog (@ "Execute%@", Nsstringfromselector (_cmd));}12 @end

1. Locks implemented using the Nslock

1 #import "LockByNSLock.h" 2 #import "TestObj.h" 3  4 @implementation lockbynslock 5  6 + (void) Executelock {7     Main thread 8     testobj *obj = [[[Testobj alloc] init]; 9     Nslock *lock = [[Nslock alloc] init];10     one     //thread (     D) Ispatch_sync (Dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{13         [lock lock];14         [obj Firstmethod];15         Sleep (2);//thread 1 execution hangs 2 seconds         [lock unlock];17     });     //Thread     Dispatch _sync (Dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{21         sleep (1);//thread 2 execution hangs 1 seconds, To ensure that thread 1 must be executed first         [lock lock];23         [obj secondmethod];24         [lock unlock];25     }];}27 @end

See the result of the print, you will see thread 1 lock, thread 2 will wait until thread 1 will lock to unlock, will not execute the Secondmethod method.

Nslock is Cocoa provides us with the most basic lock object, which is also often used, in addition to the lock and unlock method, Nslock also provides Trylock and Lockbeforedate: Two methods, the previous method will try to lock, if the lock is not available ( Locked), does not block the thread and returns no directly. Lockbeforedate: The method tries to lock before the specified date and returns no if it cannot be locked before the specified time.

2. Locks built with the Synchronized keyword

Of course, in objective-c you can also use @synchronized instructions to quickly implement the lock:

1 #import "LockBySynchronized.h" 2 #import "TestObj.h" 3  4 @implementation lockbysynchronized 5  6 + (void) Execute Lock {7     //main thread 8     testobj *obj = [[Testobj alloc] init]; 9     //     thread 111     dispatch_sync (dispatch_get_ Global_queue (Dispatch_queue_priority_default, 0), ^{12         @synchronized (obj) {             [obj firstmethod];14             Sleep (2); Thread 1 execution hangs 2 seconds         }16     });     //Thread 219     dispatch_sync (Dispatch_get_global_queue (Dispatch_ Queue_priority_default, 0), ^{20         @synchronized (obj) {             sleep (1);//thread 2 execution hangs 1 seconds to ensure that thread 1 executes first             [obj secondmethod];23         }24     });}26 @end

The @synchronized instruction uses obj as the unique identifier for the lock, and the mutex is satisfied only if the identity is the same, and if @synchronized (obj) in thread 2 is changed to @synchronized (other), thread 2 is not blocked, @ The advantage of the synchronized directive is that we do not need to explicitly create a lock object in code to implement the lock mechanism, but as a precaution, @synchronized block implicitly adds an exception-handling routine to protect the code. The processing routine releases the mutex automatically when the exception is thrown. So if you don't want an implicit exception-handling routine to bring additional overhead, you might consider using a lock object.

3. Locks implemented using the C language pthread_mutex_t

1 #import "LockByPthreadMutexT.h" 2 #import "TestObj.h" 3 #include <pthread.h> 4  5 @implementation Lockbypthrea Dmutext 6  7 + (void) Executelock {8     ///main thread 9     testobj *obj = [[Testobj alloc] init];10     __block pthread_mute x_t mutex;11     pthread_mutex_init (&mutex, NULL);     /thread     Dispatch_sync (dispatch_get_ Global_queue (Dispatch_queue_priority_default, 0), ^{15         Pthread_mutex_lock (&mutex);         Firstmethod];17         Sleep (2);//thread 1 execution hangs 2 seconds         pthread_mutex_unlock (&mutex);     /thread 222     dispatch_sync (dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{23         sleep (1);// Thread 2 execution hangs 1 seconds to ensure that thread 1 is executed first         pthread_mutex_lock (&mutex);         [obj secondmethod];26         pthread_mutex_ Unlock (&mutex);     }29 @end

pthread_mutex_t defined in Pthread.h, so remember #include

4. "Lock" implemented using GCD
The above code to build multithreading we have used the GCD Dispatch_async method, in fact, in GCD has also provided a signal mechanism, using it we can also build a "lock"

In essence, there is a difference between the semaphore and the mutex:

(1) Scope

Semaphores: Process or line threads (Linux threads only)

Mutex: Between threads

(2) When locked

Semaphore: As long as the semaphore value is greater than 0, other threads can sem_wait success, and the value of the semaphore is reduced by one after success. If value is not greater than 0, then sem_wait blocks until Sem_post is released and the value is added one. In a word, the value>=0 of the semaphore.

Mutex: Any other thread will not be able to access the protected resource as long as it is locked. If there is no lock, the resource is successful, otherwise blocking waits for the resource to become available. In a word, the vlaue of a thread mutex can be negative.

1 #import "LockByDispatchSemaphoreT.h" 2 #import "TestObj.h" 3  4 @implementation Lockbydispatchsemaphoret 5  6 + ( void) Executelock {7     ///main thread 8     testobj *obj = [[Testobj alloc] init]; 9     dispatch_semaphore_t semaphore = Dispat Ch_semaphore_create (1);     //Thread     Dispatch_sync (Dispatch_get_global_queue (dispatch_queue_ Priority_default, 0), ^{13         dispatch_semaphore_wait (semaphore, dispatch_time_forever);         [obj FirstMethod];         sleep (2);//thread 1 execution hangs 2 seconds         dispatch_semaphore_signal (semaphore); +     //Thread 220     Dispatch_sync (dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{21         sleep (1);// Thread 2 execution hangs 1 seconds to ensure that thread 1 is executed first         dispatch_semaphore_wait (semaphore, dispatch_time_forever);         Secondmethod];24         dispatch_semaphore_signal (semaphore);     }27 @end

As for the effect of the code, of course, and the previous is exactly the same, of course, the lock is used in most cases with multithreading.

Advanced usage of Locks

1.NSRecursiveLock Recursive lock

Usually when we use the lock in the code, the most prone to make a mistake is to create a deadlock, and easy to create a deadlock situation is in the recursion or loop, the following code:

 1 #import "LockByNSRecursiveLock.h" 2 #import "TestObj.h" 3 4 @implementation Lockbynsrecursivelock 5 6 + (void) Execute Lock {7///main thread 8 testobj *obj = [[Testobj alloc] init]; 9//nslock *lock = [[Nslock alloc] init];//nslock in recursion     There will be a deadlock in the scene, here you have to use Nsrecursivelock (recursive lock) nsrecursivelock *lock = [[Nsrecursivelock alloc] init];11 12//Thread 113 Dispatch_sync (Dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{14 static void (^recursivemethod) (                 Nsuinteger) Recursivemethod = ^ (Nsuinteger val) {[Lock lock];17 if (val > 0) {18 NSLog (@ "recursion, Val has a value of:%lu", (unsigned long) val); [Obj firstmethod];20 sleep (2);         Thread 1 execution hangs 2 seconds Recursivemethod (VAL-1);}23 [Lock Unlock];24};25 Recursivemethod (5); 27}); 28 29//Thread Dispatch_sync (Dispatch_get_global_queue (dispatch_queue_p Riority_default, 0), ^{31 sleep (1);//thread 2 performs a suspend of 1 seconds to ensure that thread 1 is performed first [lock lock];33 [obj secondmethod];34 [lock UNL OCK];35});}37 @end

In the above code, is a typical deadlock situation, because the thread 1 in the recursive block, the lock will be multiple times lock, so they are also blocked, because the above code is very short, so it is easy to identify the deadlock, but in the more complex code, it is not so easy to find, So how do you use locks correctly in recursion or in loops? If the lock variable is swapped with the Nsrecursivelock object, the problem is resolved, and the lock defined by the Nsrecursivelock class can be locked multiple times on the same thread without causing a deadlock. A recursive lock keeps track of how many times it is lock. Each successful lock must balance the call unlock operation. Only when all locked and unlocked operations are balanced does the lock really get released to other threads.

2.NSConditionLock Conditional Lock

When we use multi-threaded, sometimes a lock and unlock locks may not be able to fully meet our use. Because the ordinary lock can only care about the lock and not lock, and do not care about what key to unlock, and we are in the process of resource sharing, most of the situation is only to meet certain conditions to open the lock:

 1 #import "LockByNSConditionLock.h" 2 #import "TestObj.h" 3 4 @implementation Lockbynsconditionlock 5 6 + (void) Execute Lock {7///main thread 8 testobj *obj = [[Testobj alloc] init]; 9 Nsconditionlock *lock = [[Nsconditionlock alloc] In IT];10 11//Thread Dispatch_sync (dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{13 fo             R (Nsuinteger i=0; i<3; i++) {[Lock lock];15 NSLog (@ "loop, the value of I is:%lu", (unsigned long) i); 16 [Obj firstmethod];17 sleep (2); Thread 1 execution hangs 2 seconds [lock unlockwithcondition:i];19}20}]; 21 22//Thread 223 Dispatch_sync (Dispa Tch_get_global_queue (Dispatch_queue_priority_default, 0), ^{24 sleep (1);//thread 2 execution hangs 1 seconds to ensure that thread 1 is executed first//[loc K Lockwhencondition:2]; A key that needs to be identified as 2 is required for the lock operation, where thread 1 waits for the lock to be looped to its desired locking condition, and if the final non-conforming condition (for example: Thread 1 's condition is i<4), the blocking thread content is executed down Here, you have to use Trylockwhencondition: Method control//[obj secondmethod];27//[lock unlock];28 29 BOOL isLocked = [lock trylockwhencondition:2];30 [obj secondmethod];31 if (isLocked) {//locking unlocking must be For operation, otherwise will be error [lock unlock];33}34}];}36 Notoginseng @end

Thread 1 in the lock using lock, so it is not required conditions, so the smooth lock, but in the unlock used an integral type of condition, it can open the other thread is waiting for the key of the critical ground, and thread 2 needs a key identified as 2, So when thread 1 loops to the last time, it finally turns on blocking in thread 2. But even so, Nsconditionlock also with other locks, is the need to lock and unlock corresponding, just lock,lockwhencondition: and unlock,unlockwithcondition: Can be arbitrarily combined, Of course this is related to your needs.

3.NSDistributedLock Distributed lock

All of the above locks are a conflict between multiple threads, but what if there is a need to build mutually exclusive scenarios between several processes or multiple programs? This time we need to use the Nsdistributedlock, from its class name to know that this is a distributed Lock,nsdistributedlock implementation is through the file system, so use it to effectively implement the mutual exclusion between different processes, but Nsdistributedlock does not inherit from Nslock, it does not have a lock method, it only implements Trylock, unlock, breaklock, so if you need lock, you have to implement a trylock polling yourself, the following code is simplified A single demo:

1 #import "LockByNSDistributedLock.h" 2 #import "TestObj.h" 3  4 @implementation lockbynsdistributedlock 5  6 + (VO ID) executelock {7     ///main thread 8     testobj *obj = [[Testobj alloc] init]; 9     Nsdistributedlock *lock = [[nsdistributed Lock alloc] initwithpath:@ "/users/kenmu/desktop/temp/lockbynsdistributedlock"];10     one     //thread     Dispatch_sync (Dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{13         [lock breaklock];14         [ Lock trylock];15         [obj firstmethod];16         sleep (5);//thread 1 Execution hangs 5 sec         [lock unlock];18     });     20     //thread 221     dispatch_sync (dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{22 while         ( ! [Lock Trylock])             { NSLog (@ "Waiting ..."),             Sleep (1),         }26         [obj secondmethod];27         [lock unlock];28     }]; 29}30 @end

The actual scenario should look like this:

Program A:

1 Dispatch_async (Dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{2     lock = [[Nsdistributedlock] Alloc] initwithpath:@ "/users/kenmu/desktop/earning__"];3     [lock breaklock];4     [lock trylock];5     sleep (10 ); 6     [Lock unlock];7     NSLog (@ "Appa:ok"); 8});

Program B:

1 Dispatch_async (Dispatch_get_global_queue (dispatch_queue_priority_default, 0), ^{2     lock = [[Nsdistributedlock] Alloc] initwithpath:@ "/users/kenmu/desktop/earning__"];3 while     (![ Lock Trylock]) {4         NSLog (@ "appb:waiting"); 5         sleep (1); 6     }7     [lock unlock];8     NSLog (@ "Appb:ok "); 9});

Run program a first, then run program B immediately, according to the print you can clearly find that when program A just run, program B has been waiting, when about 10 seconds later, program B printed out the output of Appb:ok, the above two different programs to achieve mutual exclusion. /users/kenmu/desktop/earning __ is the address of a file or folder, and if the file or folder does not exist, the file/folder is automatically created when Trylock returns YES. At the end of the file/folder will be cleared, so in the selection of the path, you should choose a non-existent path to prevent accidental deletion of the file.

Results:

 1 2015-05-15 00:29:43.046 oclock[1675:61800] Implement lock using Nslock (normal lock; implemented Nslocking protocol) 2 2015-05-15 00:29:43.047 OCLock[ 1675:61800] Execute FirstMethod 3 2015-05-15 00:29:46.055 oclock[1675:61800] Execute secondmethod 4 2015-05-15 00:29:46.0 OCLOCK[1675:61800] Use synchronized instruction to implement lock 5 2015-05-15 00:29:46.055 oclock[1675:61800] Execute FirstMethod 6 2015-05-15 0 0:29:49.060 oclock[1675:61800] Execute secondmethod 7 2015-05-15 00:29:49.061 oclock[1675:61800] using the C language pthread_mutex_ T implement lock 8 2015-05-15 00:29:49.061 oclock[1675:61800] Execute firstmethod 9 2015-05-15 00:29:52.067 oclock[1675:61800] Execut E secondMethod10 2015-05-15 00:29:52.067 oclock[1675:61800] Use GCD dispatch_semaphore_t (semaphore) to achieve the lock 11 2015-05-15 00:29:52.068 oclock[1675:61800] Execute firstMethod12 2015-05-15 00:29:55.078 oclock[1675:61800] Execute SECONDMETHOD13 2015-05-15 00:29:55.079 oclock[1675:61800] implements the lock using Nsrecursivelock (recursive lock; implemented nslocking protocol), which can be used in a recursive scenario. If you use Nslock, a deadlock occurs in the 2015-05-15 00:29:55.079 oclock[1675:61800] recursion, the value of Val is: 515 2015-05-15 00:29:55.079 oclock[1675:61800] Execute firstMethod16 2015-05-15 00:29:57.080 oclock[1675:61800] recursion, Val value is: 417 2015-05-15 00:29:57.080 oclock[1675:61800] Execute firstMethod18 2015-05-15 00:29:59.083 oclock[1675:61800] recursion, Val value is: 319 2015-05-15 00:29:59.084 oclock[1675:61800] Execute firstMethod20 2015-05-15 00:30:01.089 oclock[1675:61800] Recursive, Val value is: 221 2015-05-15 00:30:01.089 oclock[1675:61800] Execute firstMethod22 2015-05-15 00:30:03.095 oclock[ 1675:61,800] Recursive, Val value is: 123 2015-05-15 00:30:03.095 oclock[1675:61800] Execute firstMethod24 2015-05-15 00:30:06.106 OCLOCK[1675:61800] Execute secondMethod25 2015-05-15 00:30:06.106 oclock[1675:61800] Use Nsconditionlock (conditional lock Implemented the Nslocking protocol) to implement the lock, you can use the 2015-05-15 00:30:06.107 oclock[1675:61800] loop in a scene where the condition is required for the lock operation, the value of I is: 027 2015-05-15 00:30:06.107 oclock[1675:61800] Execute firstMethod28 2015-05-15 00:30:08.112 oclock[1675:61800] loop, the value of I is: 129 2015-05-15 00:30:08.113 oclock[1675:61800] Execute firstMethod30 2015-05-15 00:30:10.115 oclock[1675:61800] In the loop, the value of I is: 231 2015-05-15 00:30:10.115 oclock[1675:61800] Execute firstMethod32 2015-05-15 00:30:13.121 oclock[ 1675:61800] Execute secondMethod33 2015-05-15 00:30:13.121 oclock[1675:61800] Use Nsdistributedlock (distributed lock; distinguish other lock types, It does not implement the Nslocking protocol) to implement the lock, which is based on the file system, automatically creates temporary files or folders for identification, automatically cleans up temporary files or folders after execution, and can be used in scenarios where mutual exclusion is required between multiple processes or multiple programs 34 2015-05-15 00:30:13.127 oclock[1675:61800] Execute firstMethod35 2015-05-15 00:30:18.129 oclock[1675:61800] Execute Secondmethod

Use of locks between threads in iOS development

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.