Dispatch Semaphore introduces

Dispatch Semaphore is a hold count signal, a count class type signal in multithreaded programming. The so-called signal is similar to the fence at the entrance of the community. Raise the fence when you can pass, lower the fence when you can’t pass. In Dispatch Semaphore, counts are used to do this. Wait when the count is 0, and subtract 1 without waiting when the count is 1 or greater.

Method of use

Create a dispatch_semaphoRE_t object. The parameter represents the initial value of the count. The following example initializes the value to 1. As you can see from the dispatch_semaphoRE_create method name, this function, like dispatch_group_t and dispatch_queue_t, must be released by dispatch_release in non-ARC mode. It can also be held using the dispatch_retain function.

 dispatch_semaphore_t semaphore_t=dispatch_semaphore_create(1);
Copy the code

The dispatch_semaphoRE_WAIT function waits for dispatch_semaphore_t to be greater than or equal to 1. When the count is greater than or equal to 1, or in standby, the count is subtracted and returned from the dispatch_semaphore_wait function. The second parameter, like dispatch_group_wait, specifies the wait time with the dispatch_time_t type value. The parameter value in this case means a permanent wait. The return values of the dispatch_semaphore_WAIT and dispatch_group_wait functions are the same.

 dispatch_semaphore_wait(semaphore_t, DISPATCH_TIME_FOREVER);
Copy the code

When the dispatch_semaphore_WAIT function returns 0, it is safe to perform the processing of the required exclusive control. When the dispatch_semaphoRE_signal function is used, the value of dispatch_semaphoRE_t is increased by 1.

Use case

// Create a queue
dispatch_queue_t queue =dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// Create a dispatch_semaphoRE_t signal object and set the count initialization value to 1
    dispatch_semaphore_t semaphore_t=dispatch_semaphore_create(1);
    NSMutableArray *array=[[NSMutableArray alloc]init];
    for (int i=0; i<50000; i++) {
        dispatch_async(queue, ^{
          Wait for semaphoRE_t until the semaphore_t count is greater than or equal to 1 to ensure that only one thread can access the array at the same time
            dispatch_semaphore_wait(semaphore_t, DISPATCH_TIME_FOREVER);
          // If semaphoRE_t is greater than or equal to 1, subtract 1 from semaphore_t and dispatch_semaphore_wait returns. At this point, the dispatch_semaphore_t count is always 0. Array data can be securely updated
            [array addObject:@(i)];
          // At the end of exclusive control processing, dispatch_semaphoRE_signal increases the semaphoRE_t count by 1.
          // The thread waiting for the count of dispatch_semaphoRE_t to increase is executed by the thread waiting first.
            dispatch_semaphore_signal(semaphore_t);
        });
    }
Copy the code

Dispatch_semaphore_t deadlock issue improved

Example: a deadlock


  dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t queue=dispatch_queue_create("111111", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"b1 %@"[NSThread currentThread]);
        [self getUserDepartmentWithSemaphore:semaphore];
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_async(queue, ^{
        NSLog(@"b2 %@"[NSThread currentThread]);
        [self getMyDepartmentListWithSemaphore:semaphore];
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_async(queue, ^{
      
        if (self.myDepartment! =nil) {[[NSOperationQueue mainQueue]addOperationWithBlock:^{
            self.selectedDepartment=self.myDepartment;
                self.companyFileHeaderView.title=self.selectedDepartment.name;
            }];
            [self loadNewData];
        }
        dispatch_semaphore_signal(semaphore);
        NSLog(@"b3 %@"[NSThread currentThread]);
    });

2021- 04- 23 18:09:05.509692+0800 IQHIPan[15507:322370] b1 <NSThread: 0x6000027f01c0>{number = 7, name = (null)}
Copy the code

Example: After improvement

 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t queue=dispatch_queue_create("111111", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"b1 %@"[NSThread currentThread]);
        [self getUserDepartmentWithSemaphore:semaphore];
    });
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"b2 %@"[NSThread currentThread]);
        [self getMyDepartmentListWithSemaphore:semaphore];
    });
   
    dispatch_async(queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        if (self.myDepartment! =nil) {[[NSOperationQueue mainQueue]addOperationWithBlock:^{
            self.selectedDepartment=self.myDepartment;
                self.companyFileHeaderView.title=self.selectedDepartment.name;
            }];
            [self loadNewData];
        }
        dispatch_semaphore_signal(semaphore);
        NSLog(@"b3 %@"[NSThreadcurrentThread]); }); Returns the result2021- 04- 23 18:11:21.149867+0800 IQHIPan[15592:324628] b1 <NSThread: 0x600003d1c200>{number = 5, name = (null)}
2021- 04- 23 18:11:21.445690+0800 IQHIPan[15592:324628] b2 <NSThread: 0x600003d1c200>{number = 5, name = (null)}
2021- 04- 23 18:11:21.775718+0800 IQHIPan[15592:324628] b3 <NSThread: 0x600003d1c200>{number = 5, name = (null)}
Copy the code

conclusion

Where there is less granularity than the Serial Dispatch Queue and dispatch_barrier_async functions and some processing requires exclusive control, dispatch_Semaphore can be useful.