我有一个macOS GUI应用程序,它在功能上也能够作为后台服务运行。即代理或守护程序。
主入口点是main。swift文件,我在其中设置了一些值并调用了一些OS调用,以了解我的应用是作为服务(Agent或Daemon)还是GUI应用启动的。
// main.swift
import Foundation
// Set some variables
// Call an ObjC++ func which does the following:
// {
// if(getppid() == 1) {
// // Prepare app to function as a daemon/agent
// // Return to swift
// } else {
// // Prepare app to function as a GUI app
// // Return to swift
// }
// Back in swift layer, start initializing the NSApplication object and
// set the NSApplicationDelegate.
我们先不讨论为什么不使用@main属性,它删除了这个样板代码。..现在,当我使用Xcode构建这个应用程序时,从builds文件夹启动它,我看到getppid()-Linux OS调用以了解父进程ID,返回1,这意味着应用程序是守护进程或代理(因为所有服务都是init进程的子进程,其pid为1)。
我没有创建任何新线程,也没有调用fork(),这两种方法都可能导致主线程返回到OS。..这导致init进程采用该应用程序。
为什么getppid()在Finder中双击启动应用时返回1?在这种情况下,Finder是父进程,对吗?
更新1:
正如在Arthur's answer和Barmar的评论(在问题中)中指出的那样-当我启动Safari,然后在终端中使用'top'命令检查其PPID时。
输出:
PID COMMAND %CPU TIME #TH #WQ #PORTS MEM PURG CMPRS PGRP PPID
5134 Safari 0.0 00:02.72 7 4 443 55M 9792K 0B 95134 1
94818 Xcode 0.0 00:17.81 10 3 569 469M 864K 0B 94818 1
如上所示,Safari和Xcode的PPID是1。
1条答案
按热度按时间mjqavswn1#
不幸的是,macOS世界中没有有效的进程树。
所有unix的东西,如getppid,将返回一些只对以unix方式启动的进程有效的东西,比如说从终端运行一些控制台二进制文件可以显示您在这里期望的行为。
GUI进程在macOS上以复杂的方式启动,包括来自真实的源进程的1+ IPC,该进程希望启动某些东西。
关于你最初的目标,我想说最简单的方法就是在它的启动列表中添加一些命令行参数或env变量,然后检查它:如果存在-应用程序作为代理/守护程序启动,如果不存在-使用GUI逻辑。
我在here之前已经回答了一个类似的问题(稍微复杂一点),如果您想了解更多关于这个主题的内容