![](/img/trans.png)
[英]Copied Cocoa Framework searches /Library/Frameworks/… only. How can I make it search binary within itself?
[英]Why can't I use cocoa frameworks in different forked processes?
我正在玩NSSound
类在我自己的后台进程中播放声音,以便不阻止用户输入。 我决定调用fork()
但这给了我一些问题。 在分配声音的那一刻,分叉进程崩溃。 有趣的是,如果我构造一个只调用fork()
的示例,那么子进程可以NSSound
调用NSSound
,只有在fork()
调用之前我尝试使用其他cocoa API时才会出现崩溃。 使用crashme?()
调用注释这个例子:
#import <AppKit/AppKit.h>
#import <math.h>
#define FILENAME \
"/System/Library/Components/CoreAudio.component/" \
"Contents/SharedSupport/SystemSounds/dock/drag to trash.aif"
void crashme1(void)
{
NSString *path = [[NSString alloc] initWithUTF8String:"false file"];
NSSound *sound = [[NSSound alloc]
initWithContentsOfFile:path byReference:YES];
}
void crashme2(void)
{
NSInteger tag = 0;
[[NSWorkspace sharedWorkspace]
performFileOperation:NSWorkspaceRecycleOperation
source:@"." destination:nil
files:[NSArray arrayWithObject:@"false file"] tag:&tag];
}
double playAif(void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *path = [[NSString alloc] initWithUTF8String:FILENAME];
NSSound *sound = [[NSSound alloc]
initWithContentsOfFile:path byReference:YES];
[path release];
if (!sound) {
[pool release];
return -1;
}
const double ret = [sound duration];
[sound play];
[sound autorelease];
[pool release];
return ret;
}
int main(int argc, char *argv[])
{
//crashme1();
//crashme2();
int childpid = fork();
if (0 == childpid) {
printf("Starting playback\n");
double wait = playAif();
sleep(ceil(wait));
wait = playAif();
sleep(ceil(wait));
printf("Finished playback\n");
}
return 0;
}
当我从命令行运行它时,它可以工作,但如果我取消注释其中一个crashme?()
函数的调用,分叉进程中的回放永远不会启动。 是因为任何Cocoa框架API都不是异步信号安全的吗? 是否有办法通过以某种方式包装它们来使调用异步信号安全?
我将引用Leopard CoreFoundation Framework发行说明。 我不知道他们是否还在线,因为Apple倾向于取代而不是扩展Core Foundation发行说明。
CoreFoundation和fork()
由于fork()的行为,CoreFoundation不能在fork()的子端使用。 如果你fork(),你必须使用某种类型的exec *()调用,并且你不应该在exec *()之前在子元素中使用CoreFoundation API。 这适用于使用CoreFoundation的所有更高级别的API,并且由于您无法知道这些更高级别的API正在做什么,以及它们是否使用CoreFoundation API,因此您也不应使用任何更高级别的API。 这包括使用守护进程()函数。
另外,根据POSIX,只有async-cancel-safe函数可以安全地在fork()的子端使用,所以即使使用较低级别的libSystem / BSD / UNIX API也应该保持在最低限度,理想情况下只能保持异步 - 防伪功能。
这一直都是事实,过去在各种Cocoa开发人员填写清单上都有这样的说明。 但是CoreFoundation现在采取了一些更强有力的措施来“强制执行”这个限制,所以我们认为添加一个发行说明也是值得的。 当某些东西使用API时,会向stderr写入一条消息,而在fork()之后,这个API在CoreFoundation中肯定是不安全的。 但是,如果文件描述符2已关闭,则不会收到任何消息或通知,这太糟糕了。 我们试图以一种非常容易识别的方式使进程终止,并且做了一段时间,这非常方便,但是向后的二进制兼容性阻止了我们这样做。
换句话说,除了执行一个新程序之外,在fork()
的子方面做很多事情从来都不安全。
除了一般的POSIX禁令之外,经常提到的解释是:a)现在几乎所有的Cocoa程序都是多线程的,GCD之类的东西也是如此。 B)当你fork()
,只有调用线程存活到子进程中; 其他线程只是消失了。 由于这些线程可能一直在操纵共享资源,因此子进程不能依赖于健全状态。 例如, malloc()
实现可能具有锁定以保护共享结构,并且在fork()
时锁定可能已由其中一个已经消失的线程保持。 因此,如果剩下的线程试图分配内存,它可能会无限期挂起。 其他共享数据结构可能只是处于损坏状态。 等等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.