我尝试使用Distributed对象在其他进程中显示窗口。 进程A通过显示对话框的进程B通过分布式对象方法远程调用。如果我试图等待结果,会发生错误。 该方法看起来像:
-(BOOL)showWindow //method invoked through distributed objects
{
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[object showDialog:^(BOOL result){ //this methods creates and display window
NSLog(@"Block called");
dispatch_semaphor_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
return YES;
}
showWindow函数永远不会结束。如果我评论dispatch_semaphore_wait,则显示“Block called”并显示窗口。 我检查了不同的变体同步,我尝试使用dispatch_sync或async运行此代码,但没有任何帮助。
我将感激不尽。 KON
答案 0 :(得分:0)
问题是DO要求运行循环运行以便处理双方之间的通信。基本上,您展示的代码向远程端发送请求,该远程端托管object
代理的真实对象。该请求带有对本地块对象的引用。远程方有效地获得了代理。
一段时间后,远程端调用其块代理。这会导致请求被发送回此进程和线程。但是,此线程无法接收该请求,因为它在dispatch_semaphore_wait()
中被阻止。它没有参加任何沟通渠道。
所以,双方都陷入僵局。本地方面永远等待永远不会发出信号的信号量,并且远程端会永远等待其运行块完成的请求。
另一种方式是,信号量是远程进程发出的 信号。你已经要求它由等待它的同一个线程发出信号。只是如果可能的话,这个线程会响应另一个进程发送的事件。让一个线程负责发信号通知它正在等待的信号量是一个非常明确的,立即的自我死锁。
您可以将-showWindow
更改为不同步吗?为什么它使用信号量并等待?为什么它不能只是触发请求然后返回到调用代码,这不应该假设对话框已经完成,而是一直返回到主事件循环?无论应该发生什么工作,都应将“next”放入完成块,并在对话框完成时异步调用。
如果你真的需要这个方法同步,那么你将不得不使用run循环来代替调度信号量。类似的东西:
-(BOOL)showWindow //method invoked through distributed objects
{
__block BOOL done = NO;
[object showDialog:^(BOOL result){ //this methods creates and display window
NSLog(@"Block called");
done = YES;
}];
NSString* mode = @"com.yourcompany.yourapp.privatemode";
NSConnection* conn = [(NSDistantObject*)object connectionForProxy];
[conn addRequestMode:mode];
while (!done)
[[NSRunLoop currentRunLoop] runMode:mode beforeDate:[NSDate distantFuture]];
[conn removeRequestMode:mode];
return YES;
}
实际上,您应该在第一次创建连接时将私有模式添加到连接中,并将其保留在生命周期中。您不希望使用任何预定义模式,因为当您等待并且您的代码意外重入时,意外事件可能会触发,等等。