2009-11-30 45 views
1

这里是我的代码的简化版本:派生进程似乎吃了某些代码行 - Objective-C的

- (IBAction)convert:(id)sender 
{ 
    /* these two lines are ignored */ 
    [textbox setStringValue:@"converting"]; 
    [convertButton setEnabled:NO]; 

     pid_t pid; 
     if((pid=fork())==-1) 
     { 
      [log setStringValue:@"couldn't fork a new process."]; 
      converting = 0; 
     [convertButton setEnabled:YES]; 
      return; 
     }else if (pid==0) 
     { 
      //this is the child 
      sleep(2); 
      exit(0); 
     }else{ 
      int status; 
      waitpid(pid,&status,0); 
     } 
    } 
} 

这是一个非常基本的fork()调用。问题在于,最上面的两条线(标有评论)被忽略......他们似乎并没有执行,直到分叉的孩子退出之后。为什么?

编辑:我能做些什么来解决它?

回答

9

你真的真的真的不想叫fork()在Cocoa应用程序。在这样做时,大约有数十亿个不同的陷阱,其中大部分涉及各种资源(如端口和其他系统绑定基础设施)如何在边界上幸存下来。线程也会导致各种各样的地狱。

改为使用NSTask。虽然它在内部有效地执行,但它会非常小心地确保它正确完成。

+0

这就是它。对于任何有兴趣的人,我已发布回复我使用的代码。 – 2009-11-30 03:22:27

3

也许是因为您的代码在GUI可以改变状态之前必须返回到主事件循环?或者,稍微有些变化,因为运行GUI的线程在代码执行内核级wait()时被阻塞?

+1

这听起来很可能......你知道任何解决方案吗? – 2009-11-30 02:05:20

+0

解决方案是不要阻止。更好的解决方案是根本不使用fork()。分叉GUI级别的过程非常难以正确执行。使用'NSTask';我的答案提供了更多细节,为什么。 – bbum 2009-11-30 02:16:01

+0

非常好。我想到一个知道API早晚会出现的人...... – DigitalRoss 2009-11-30 02:33:09

1

bbum得到了这正确的。这里是我最终使用的代码:

- (IBAction)convert:(id)sender 
{ 
    task = [[NSTask alloc] init]; 
    [task setLaunchPath: @"/usr/local/bin/lame"]; 

    NSArray *arguments; 
    arguments = [NSArray arrayWithObjects: file,outputFile, nil]; 
    [task setArguments: arguments]; 

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskFinished:) name:NSTaskDidTerminateNotification object:task]; 

    [task launch]; 
} 
- (void) taskFinished:(NSNotification *)note { 
    // code here executes after process finishes  
} 
+0

很高兴有帮助。仅供参考:您在该代码中阻止主事件循环;即在子过程退出之前UI不会更新。没有什么大不了的,如果有意或子程序执行的时间极短...... – bbum 2009-11-30 03:38:21

+0

@bbum:是的,我被告知,在另一个问题:)编辑以反映这个线程的更好的解决方案:http:// stackoverflow.com/questions/1817726/ignoring-user-input-while-waiting-for-a-task-objective-c – 2009-11-30 04:19:21