在一个队列解锁 NSRecursiveLock 后,其他队列仍在等待

发布于 2025-01-15 11:38:09 字数 2581 浏览 2 评论 0 原文

我有一些代码不是线程安全的,所以我尝试使用 NSRecursiveLock 来防止我的工作队列和主线程同时访问某些属性。我创建了两个工作队列(工作队列和等待队列),工作队列来做一些繁重的工作。为了防止阻塞主线程,我创建了另一个等待队列来等待锁,这样我就可以在获得锁后异步到主线程。

我面临两个问题:

  1. 工作队列解锁后,等待队列仍在等待。
  2. 代码将得到两种输出

我认为输出应该是

1. work queue get lock
2. wait queue wait lock
3. post notification from work queue
noti called
unlock
get lock
4. main thread do work

但我得到输出:

[Output 1]
1. work queue get lock
2. wait queue wait lock
3. post notification from work queue
noti called
unlock

[Output 2]
1. work queue get lock
2. wait queue wait lock
get lock
4. main thread do work
3. post notification from work queue
noti called
unlock

@interface ViewController ()
@property (nonatomic) NSLock *lock;
@property (nonatomic) NSRecursiveLock *recursiveLock;
@property (nonatomic) dispatch_queue_t queue;
@property (nonatomic) dispatch_queue_t lockWaitQueue;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
    _lockWaitQueue = dispatch_queue_create("wait_queue", DISPATCH_QUEUE_SERIAL);

    [[NSNotificationCenter defaultCenter] addObserverForName:@"noti" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
        NSLog(@"noti called");
    }];
    _lock = [NSLock new];
    _recursiveLock = [NSRecursiveLock new];
    [self tryFixDeadLockCace];
}

- (void)tryFixDeadLockCace {
    NSRecursiveLock *lock = _recursiveLock;
    dispatch_queue_t queue = _queue;
    dispatch_queue_t lockWaitQueue = _lockWaitQueue;
    NSLog(@"1. work queue get lock");
    dispatch_async(queue, ^{
        [lock lock];
        dispatch_async(dispatch_get_main_queue(), ^{
            dispatch_async(lockWaitQueue, ^{
                NSLog(@"2. wait queue wait lock");
                [lock lock];
                NSLog(@"get lock");
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSLog(@"4. main thread do work");
                    [lock unlock];
                });
            });
        });
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"3. post notification from work queue");
        [[NSNotificationCenter defaultCenter] postNotificationName:@"noti" object:nil];
        NSLog(@"unlock");
        [lock unlock];
    });
}

- (void)noti {
    
}
@end

I have some code not thread safe, So I tried to use NSRecursiveLock to prevent my work queue and main thread access some properties at the same time. I create two work queue(work queue and wait queue), work queue to do some heavy work. In order to prevent block main thread, I create another wait queue to wait the lock, so I can async to main thread after I get the lock.

I face two problem:

  1. after the work queue unlock, wait queue still waiting.
  2. code will get two kind of output

I think the output should be

1. work queue get lock
2. wait queue wait lock
3. post notification from work queue
noti called
unlock
get lock
4. main thread do work

but I get Output:

[Output 1]
1. work queue get lock
2. wait queue wait lock
3. post notification from work queue
noti called
unlock

[Output 2]
1. work queue get lock
2. wait queue wait lock
get lock
4. main thread do work
3. post notification from work queue
noti called
unlock

@interface ViewController ()
@property (nonatomic) NSLock *lock;
@property (nonatomic) NSRecursiveLock *recursiveLock;
@property (nonatomic) dispatch_queue_t queue;
@property (nonatomic) dispatch_queue_t lockWaitQueue;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    _queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
    _lockWaitQueue = dispatch_queue_create("wait_queue", DISPATCH_QUEUE_SERIAL);

    [[NSNotificationCenter defaultCenter] addObserverForName:@"noti" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
        NSLog(@"noti called");
    }];
    _lock = [NSLock new];
    _recursiveLock = [NSRecursiveLock new];
    [self tryFixDeadLockCace];
}

- (void)tryFixDeadLockCace {
    NSRecursiveLock *lock = _recursiveLock;
    dispatch_queue_t queue = _queue;
    dispatch_queue_t lockWaitQueue = _lockWaitQueue;
    NSLog(@"1. work queue get lock");
    dispatch_async(queue, ^{
        [lock lock];
        dispatch_async(dispatch_get_main_queue(), ^{
            dispatch_async(lockWaitQueue, ^{
                NSLog(@"2. wait queue wait lock");
                [lock lock];
                NSLog(@"get lock");
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSLog(@"4. main thread do work");
                    [lock unlock];
                });
            });
        });
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"3. post notification from work queue");
        [[NSNotificationCenter defaultCenter] postNotificationName:@"noti" object:nil];
        NSLog(@"unlock");
        [lock unlock];
    });
}

- (void)noti {
    
}
@end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

司马昭之心 2025-01-22 11:38:09

如果用户使用NSRecursiveLock,不应该使用GCD,因为锁定和解锁可能不在同一个线程上

if user NSRecursiveLock, should not use GCD, because lock an unlock may not on the same thread

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文