大中央调度块线程安全吗?

Are grand central dispatch blocks thread safe?

本文关键字:安全 线程 调度      更新时间:2023-10-16

我有一个名为TestView的类,它有一个名为'loader'的实例变量,类型为loader。我在TestView上创建了一个方法来实例化加载器;然后在2秒后开始加载。

这个方法是这样的:

-(void) createLoaderAndStartLoadingTwoSecondsLater{
    loader =  Loader();
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        printf("DISPATCHING AFTER %i seconds", i);
        loader->load(*urlRequest);
    });
}

在其他地方,有一个dealloc方法:

-(void) dealloc
{
    delete loader; 
}

在2秒计时器结束之前调用dealloc是可能的。在这种情况下,我希望dispatch_after块永远不会执行。

编辑:我想这样做:

  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        printf("DISPATCHING AFTER %i seconds", i);
        if ( !hasBeenDeleted( loader ) ){
             loader->load(*urlRequest);
        }
    });

但我担心两件事:

  • 我不知道如何实现一个已被删除的函数
  • 我担心hasBeenDeleted会返回false,然后加载器会在另一个线程上被删除。

所以我真的想这样做:

  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        printf("DISPATCHING AFTER %i seconds", i);
        lockTheOtherThreads();
        if ( !hasBeenDeleted( loader ) ){
             loader->load(*urlRequest);
        }
        unlockTheOtherThreads();
    });

但我也不知道如何实现lockTheOtherThreads()

假设你有这个

@implementation MyClass {
    Loader *loader;
} 
-(void)createLoaderAndStartLoadingTwoSecondsLater{
    loader = new Loader();
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        printf("DISPATCHING AFTER %i seconds", i);
        loader->load(*urlRequest);
        //self->loader->load(*self->urlRequest);
    });
}

您创建的调度块将保留对self的强引用,这意味着dealloc在块执行之前不会被调用。

也使用unique_ptr,所以你不需要调用delete。或者shared_ptr + atomic_load,如果加载器可以被多个线程访问。

@implementation MyClass {
    std::unique_ptr<Loader> loader;
} 
-(void)createLoaderAndStartLoadingTwoSecondsLater{
    loader.reset(new Loader()); // will delete previous loader if it exist
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        printf("DISPATCHING AFTER %i seconds", i);
        loader->load(*urlRequest);
    });
}
// you don't need dealloc anymore

更新:

您可以捕获块中对self的弱引用,以避免它延长self的生存期

-(void)createLoaderAndStartLoadingTwoSecondsLater{
    loader.reset(new Loader()); // will delete previous loader if it exist
    __weak typeof(self) weakSelf = self; // a weak reference to self
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        typeof(weakSelf) strongSelf = weakSelf;
        printf("DISPATCHING AFTER %i seconds", i);
        if (strongSelf) { // if still alive
            strongSelf->loader->load(*urlRequest);
        } // else it is deallocated
    });
}

您实际上想要做什么并不清楚。事情不仅仅是"线程安全",你还需要说明你想做什么。

一旦dealloc被调用,当dealloc返回时,该对象将消失。就算别人想要保留也没关系。看来你把Objective-C和c++搞混了。在c++中调用delete时,对象就消失了。

我建议你仔细阅读Objective-C中的弱指针,远离c++。