调度一次 (dispatch_once) 单例冻结/锁定 objective c
Dispatch once (dispatch_once) singleton freezes / locks in objective c
这行代码在我的 awakeFromFetch
方法中调用,该方法位于实现 NSManagedObject
的自定义托管对象内。特别是这条线正在调用我的单例网络管理器 class 称为 sharedManager
.
[self setSync:(![[WKNetworkManager sharedManager] objectHasPendingRequests:self.objectID]) ];
dispatch_once 块将被命中,如下所示。请注意,它的实现方式很好,如图所示 here:
dispatch_once 调用然后转到 once.h 并在此处冻结在突出显示的行上:
这是堆栈跟踪:
所有这些都是在尝试加载以前保存的网络队列文件时发生的。应用程序完全关闭以保存,然后再次启动,然后出现此 freezing/locking。
我什至尝试按照建议 here 使用此代码来解决问题,但没有成功。但是无论如何改变它可能并不重要,因为我原来的 dispatch_once 代码已经运行了很长时间。只是在这个特殊情况下。
if ([NSThread isMainThread])
{
dispatch_once(&onceToken, ^{
stack = [[KACoreDataStack alloc] init];});
}
else
{
dispatch_sync(dispatch_get_main_queue(), ^{
dispatch_once(&onceToken, ^{
stack = [[KACoreDataStack alloc] init];});
});
}
到目前为止,这些是我解决此类问题的来源:
- Code execution stops on using thread safe Singleton initialization code
- http://cocoasamurai.blogspot.jp/2011/04/singletons-your-doing-them-wrong.html
- http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial
- ios singleton class crashes my app
- http://benalpert.com/2014/04/02/dispatch-once-initialization-on-the-main-thread.html
- http://www.bignerdranch.com/blog/dispatch_once-upon-a-time/
感谢您的帮助!
臭小子,问的真好
这里的问题是对 dispatch_once 的递归调用会死锁。如果您需要确切的详细信息,you can find them with the source here。所以你需要重写以避免这种情况。
我的观点是,导致此 -loadQueueFromDisk
调用的任何因素都存在架构失误。你绝对不想做任何在执行时间上可能不受限制的事情,就像在dispatch_once
中关闭并从磁盘加载一些东西一样。你想要做的是创建一个可寻址的单身人士并退出的绝对最低限度。然后,给它一个 "Initializing" 的内部状态,并将磁盘加载的东西传送到某处的非阻塞队列中。这样,所有不依赖于从磁盘加载的东西的东西都可以继续,而所有依赖于从磁盘加载的东西的东西都可以将自己添加到磁盘加载所在的队列中,或者每隔几百毫秒检查一次以查看如果它处于 "Initialized" 状态,或者类似的状态。
感谢 alexcurylo 的帮助,排入 loadFromDisk 作业解决了这个问题。为了不让人们感到困惑,碰巧在下面的这段代码中,我正在排队一个从磁盘加载数组(充当保存的用户请求队列)的作业。您可能正在排队任何作业,例如加载图像等。我的 sharedManager class(调用磁盘加载)中的以下代码有效,如下所示:
-(void) loadQueueFromFileByQueueing
{
//Create a Queue
/* Note that fileStrQueue should be added to the .h file as NSOperationQueue *fileStrQueue;*/
fileStrQueue = [[NSOperationQueue alloc] init];
//Create an operation which will invoke method loadQueueFromDisk
NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadQueueFromDisk) object:nil];
//Add this operation to the queue
[fileStrQueue addOperation:operation];
//Releasing the above operation as it is already retained by the queue.
// [operation release]; // If you are using ARC, this won't be necessary
}
这行代码在我的 awakeFromFetch
方法中调用,该方法位于实现 NSManagedObject
的自定义托管对象内。特别是这条线正在调用我的单例网络管理器 class 称为 sharedManager
.
[self setSync:(![[WKNetworkManager sharedManager] objectHasPendingRequests:self.objectID]) ];
dispatch_once 块将被命中,如下所示。请注意,它的实现方式很好,如图所示 here:
dispatch_once 调用然后转到 once.h 并在此处冻结在突出显示的行上:
这是堆栈跟踪:
所有这些都是在尝试加载以前保存的网络队列文件时发生的。应用程序完全关闭以保存,然后再次启动,然后出现此 freezing/locking。
我什至尝试按照建议 here 使用此代码来解决问题,但没有成功。但是无论如何改变它可能并不重要,因为我原来的 dispatch_once 代码已经运行了很长时间。只是在这个特殊情况下。
if ([NSThread isMainThread])
{
dispatch_once(&onceToken, ^{
stack = [[KACoreDataStack alloc] init];});
}
else
{
dispatch_sync(dispatch_get_main_queue(), ^{
dispatch_once(&onceToken, ^{
stack = [[KACoreDataStack alloc] init];});
});
}
到目前为止,这些是我解决此类问题的来源:
- Code execution stops on using thread safe Singleton initialization code
- http://cocoasamurai.blogspot.jp/2011/04/singletons-your-doing-them-wrong.html
- http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial
- ios singleton class crashes my app
- http://benalpert.com/2014/04/02/dispatch-once-initialization-on-the-main-thread.html
- http://www.bignerdranch.com/blog/dispatch_once-upon-a-time/
感谢您的帮助!
臭小子,问的真好
这里的问题是对 dispatch_once 的递归调用会死锁。如果您需要确切的详细信息,you can find them with the source here。所以你需要重写以避免这种情况。
我的观点是,导致此 -loadQueueFromDisk
调用的任何因素都存在架构失误。你绝对不想做任何在执行时间上可能不受限制的事情,就像在dispatch_once
中关闭并从磁盘加载一些东西一样。你想要做的是创建一个可寻址的单身人士并退出的绝对最低限度。然后,给它一个 "Initializing" 的内部状态,并将磁盘加载的东西传送到某处的非阻塞队列中。这样,所有不依赖于从磁盘加载的东西的东西都可以继续,而所有依赖于从磁盘加载的东西的东西都可以将自己添加到磁盘加载所在的队列中,或者每隔几百毫秒检查一次以查看如果它处于 "Initialized" 状态,或者类似的状态。
感谢 alexcurylo 的帮助,排入 loadFromDisk 作业解决了这个问题。为了不让人们感到困惑,碰巧在下面的这段代码中,我正在排队一个从磁盘加载数组(充当保存的用户请求队列)的作业。您可能正在排队任何作业,例如加载图像等。我的 sharedManager class(调用磁盘加载)中的以下代码有效,如下所示:
-(void) loadQueueFromFileByQueueing
{
//Create a Queue
/* Note that fileStrQueue should be added to the .h file as NSOperationQueue *fileStrQueue;*/
fileStrQueue = [[NSOperationQueue alloc] init];
//Create an operation which will invoke method loadQueueFromDisk
NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadQueueFromDisk) object:nil];
//Add this operation to the queue
[fileStrQueue addOperation:operation];
//Releasing the above operation as it is already retained by the queue.
// [operation release]; // If you are using ARC, this won't be necessary
}