This is the 19th day of my participation in the Gwen Challenge in November. Check out the details: The last Gwen Challenge in 2021.
Dispatch Semaphore is what we call a GCD Semaphore, a signal that holds counts.
Dispatch Semaphore provides three functions:
dispatch_semaphore_creat
: Creates a Semaphore and initializes the total amount of signalsdispatch_semaphore_signal
: Sends a signal that increases the total number of signals by 1dispatch_semaphore_wait
: You can decrease the total semaphore by 1. When the total number of signals reaches 0, it will wait (blocking thread), otherwise it will execute normally.
Dispatch Semaphore is mainly used in practical development for:
- Keep thread synchronization and convert asynchronous execution tasks to synchronous execution tasks
- Keep the thread safe and lock the thread
Keep threads in sync:
dispatch_semaphore_t semaphore = dispatch_semaphore_creat(0);
__block NSInteger number = 0;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
number = 100;
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"semaphore---end,number = %zd",number);
Copy the code
The dispatch_SEMapHORE_wait lock blocks the current thread. After dispatch_semaphore_signal is unlocked, the current thread continues to execute.
Keep the thread safe and lock the thread
In thread safety dispatch_semaphore_wait can be treated as locking and dispatch_semaphore_signal as unlocking
_semaphore = dispatch_semaphore_creat(1);
Copy the code
Notice that the initial semaphore here is 1.
- (void)asyncTask{ dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER); count++; sleep(1); NSLog(@" execute task: %zd",count); dispatch_semaphore_signal(_semaphore); }Copy the code
Asynchronously invoke asyncTask concurrently
for (NSInteger i = 0; i < 100; I++) {dispatch_async(dispatch_get_global_queue(0,0),^{[self asyncTask]; }); }Copy the code
Then I found that the print was executed sequentially from task 1 to 100, without the occurrence of two tasks being executed when I was upset.
The reason is as follows: If asyncTask is executed concurrently in a child thread, the first one added to the concurrent queue decreases the semaphore by 1, and the semaphore is equal to 0, and the next task can be executed. For other tasks in the concurrent queue, since the semaphore is not equal to 0 at this time, you must call dispatch_semaphore_signal to add 1 to the semaphore after the execution of the current task is completed, and then you can continue to execute the next task, and so on, so as to achieve the purpose of thread locking.
NSThreat+ Runloop implements resident threads
A common scenario for nsthreads in real life development is to implement resident threads.
- Because each time to open a child thread will consume CPU, in the case of frequent use of child thread, frequent open child thread will consume a lot of CPU, and the creation of threads are completed after execution is released, can not be used again, so how to create a thread can make it work again? That is, create a resident thread.
First, resident threads since resident threads are resident, we can use GCD to implement a singleton to hold nsThreads
Static NSThread *shareThread = nil; static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate,^{ shareThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadTest) object:nil]; [shareThread setName:@"threadTest"]; [shareThread start]; }); return shareThread; }Copy the code
Does this prevent thread creation from being destroyed?
[self performSelector:@selector(test) onThread:[viewController shareThread] withObject:nil waitUntilDone:NO];
- (void)test{
NSLog(@"test:%@",[NSThread currentThread]);
}
Copy the code
The test method is not called if it is not printed. You can use runloop to keep the thread resident
Static NSThread *shareThread = nil; static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate,^{ shareThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadTest) object:nil]; [shareThread setName:@"threadTest"]; [shareThread start]; }); return shareThread; } - (void)threadTest{ @autoreleasepool{ NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; [runLoop addPort:[NSMachPort port] formode:NSdefaultRunLoopMode]; [runLoop run]; }}Copy the code
And then I call performSelector and I get printed.