iOS-GCD 멀티스레드 Lock 사례

6845 단어
1. 잠금 장면: 메인 라인이 메인 라인을 호출합니다.
- (void)deadLockCase1 {
    NSLog(@"1"); //   1
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"2"); //   2
    });
    NSLog(@"3"); //   3
}

     :1 ,      。

4 : 컨트롤러 출력에서 알 수 있듯이 퀘스트 2와 퀘스트 3이 실행되지 않았습니다. 이때 이미 잠겼습니다.디스패치 때문에...sync는 동기화되어 있으며, 그 자체가 현재 라인을 막습니다. 이 때 주 라인을 막습니다.현재 Block은 주 라인이 실행되기를 기다리고 있어 주 라인이 주 라인을 기다리고 자신이 자신을 기다리는 상황을 형성하여 사라진 자물쇠를 형성했다
1、비동기 디스패치async 실행
NSLog(@"1"); //   1
dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"2"); //   2
 });
NSLog(@"3"); //   3

     :1 3 2

2. 주 스레드에서 운행하지 않고 하위 스레드에 놓는다
NSLog(@"1"); //   1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSLog(@"2"); //   2
});
NSLog(@"3"); //   3

     :1 2 3

참고: Block에서 UI 새로 고침 작업이 있으면 하위 스레드에서 실행할 수 없습니다.crash
2. 사라진 장면2: (직렬 대기열 동기화 자신을 끼워넣기)
- (void)deadLockCase2 {
    dispatch_queue_t aSerialDispatchQueue = dispatch_queue_create("com.test.deadlock.queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1"); //  1
    dispatch_sync(aSerialDispatchQueue, ^{
        NSLog(@"2"); //  2
        dispatch_sync(aSerialDispatchQueue, ^{
            NSLog(@"3"); //  3
        });
        NSLog(@"4");  //  4
    });
    NSLog(@"5");  //  5
}
     :1 2 ,   2      。

4 : 콘솔 출력 결과를 보면 퀘스트 2를 실행한 후 잠금이 꺼졌습니다.이 예에서 두 GCD가 모두 사용하는 동기화 방식이고 같은 직렬 대기열이기 때문에 이전의 예와 같이 자신이 자신을 기다리는 상황이 발생하여 사라진 자물쇠가 형성되었다
1. 두 번째 GCD를 비동기식으로 변경
 - (void)deadLockCase2 {
    dispatch_queue_t aSerialDispatchQueue = dispatch_queue_create("com.test.deadlock.queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1"); //  1
    dispatch_sync(aSerialDispatchQueue, ^{
        NSLog(@"2"); //  2
        dispatch_async(aSerialDispatchQueue, ^{
            NSLog(@"3"); //  3
        });
        NSLog(@"4");  //  4
    });
    NSLog(@"5");  //  5
}
     :1 2 4 5 3

그러나 첫 번째 GCD를 비동기식으로 변경하면 문제가 해결되지 않습니다.
 - (void)deadLockCase2 {
    dispatch_queue_t aSerialDispatchQueue = dispatch_queue_create("com.test.deadlock.queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1"); //  1
    dispatch_async(aSerialDispatchQueue, ^{
        NSLog(@"2"); //  2
        dispatch_sync(aSerialDispatchQueue, ^{
            NSLog(@"3"); //  3
        });
        NSLog(@"4");  //  4
    });
    NSLog(@"5");  //  5
}

     :
1
5
2

4 첫 번째 GCD는 비동기적이지만 두 번째 GCD는 동기화되고 두 번째 GCD는 첫 번째 GCD가 끝나기를 기다리고 첫 번째 GCD의 Block은 첫 번째 GCD가 끝나기를 기다리기 때문에 사라진 자물쇠가 형성된다.주: 상기에서 두 번째 GCD를 비동기적으로 바꾸고 첫 번째 GCD가 동기화되는 장면에 대해 자물쇠가 사라지지 않습니다. 두 번째 GCD가 비동기이기 때문에 첫 번째 GCD가 실행될 때까지 기다릴 필요가 없습니다. 이것은 첫 번째 GCD와 동기화 관계가 없습니다.이것은 첫 번째 GCD가 실행되는 동시에 자신의 Block을 실행하는 코드입니다.
2. 두 GCD 모두 비동기식으로 변경
 - (void)deadLockCase2 {
    dispatch_queue_t aSerialDispatchQueue = dispatch_queue_create("com.test.deadlock.queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1"); //  1
    dispatch_async(aSerialDispatchQueue, ^{
        NSLog(@"2"); //  2
        dispatch_async(aSerialDispatchQueue, ^{
            NSLog(@"3"); //  3
        });
        NSLog(@"4");  //  4
    });
    NSLog(@"5");  //  5
}

     :
1
5
2
4
3

3. 서로 다른 직렬 대기열을 사용
 - (void)deadLockCase2 {
    dispatch_queue_t aSerialDispatchQueue1 = dispatch_queue_create("com.test.deadlock.queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t aSerialDispatchQueue2 = dispatch_queue_create("com.test.deadlock.queue2", DISPATCH_QUEUE_SERIAL);
    NSLog(@"1"); //  1
    dispatch_sync(aSerialDispatchQueue1, ^{
        NSLog(@"2"); //  2
        dispatch_sync(aSerialDispatchQueue2, ^{
            NSLog(@"3"); //  3
        });
        NSLog(@"4");  //  4
    });
    NSLog(@"5");  //  5
}

     :
1
2
3
4
5

3. 사쇄 장면: 신호량 막힘 주선정
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    NSLog(@"semaphore create!");
    dispatch_async(dispatch_get_main_queue(), ^{
        dispatch_semaphore_signal(semaphore);
        NSLog(@"semaphore plus 1");
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"semaphore minus 1");
}

4 현재 실행 중인 라인이 주 라인이면 상기 코드에 자물쇠가 사라집니다.디스패치 때문에...semaphore_wait(semaphore, DISPATCH TIME FOREVER)는 현재 스레드를 차단하고 대기 시간은 DISPATCHTIME_FOREVER - 영원히 기다리세요. 그러면 현재 라인인 메인 라인을 영원히 막을 수 있습니다.메인 라인의 디스패치semaphore_signal(semaphore)이 실행되지 않고 dispatchsemaphore_wait는 디스패치를 기다리고 있습니다semaphore_signal이 신호량을 바꾸면 사라진 자물쇠가 형성됩니다 전역 스케줄링 대기열과 같은 신호량을 병렬 대기열로 옮겨야 한다.다음 장면은 직렬 대기열로 이동해도 됩니다.그러나 직렬 대기열은 잠길 수 있습니다. (dispatch semaphore signal 방법을 실행해도 직렬 대기열에 대응하는 경우, 즉 앞서 언급한 직렬 대기열이 직렬 대기열을 끼워 넣는 장면입니다.)
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        NSLog(@"semaphore create!");
        dispatch_async(dispatch_get_main_queue(), ^{
            dispatch_semaphore_signal(semaphore);
            NSLog(@"semaphore plus 1");
        });
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"semaphore minus 1");
    });
}

          

다음 코드의 운행 결과는 어떻습니까?
-(void)viewDidLoad {
    
    [super viewDidLoad];
    
    NSLog(@"1");
    
    dispatch_sync(dispatch_get_main_queue(), ^{
        
        NSLog(@"2");
    });
    
    NSLog(@"3");
}

출력만: 1.뒤에 붕괴되었습니다. (dispatch get main queue (),^ {...}.너를 기다리게 하고 내가 너를 기다리게 하고 결국은 자물쇠가 사라지게 할 것이다.
참고 자료
4. 다음 코드 인쇄 순서는?
//dispatchqueue_create 함수로 생성된 concurrent Dispatch Queue 대기열과 함께 dispatch 사용queue_t queue = dispatch_queue_create("test_queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
    NSLog(@"----1-----%@", [NSThread currentThread]);
});

dispatch_barrier_async(queue, ^{//      barrier    
    NSLog(@"----2----barrier-----%@", [NSThread currentThread]);
});

dispatch_async(queue, ^{
    NSLog(@"----3-----%@", [NSThread currentThread]);
});
1、2、3

좋은 웹페이지 즐겨찾기