Я пытаюсь передать сигналы из моего pyobjc gui (меню в строке состояния osx) в основной процесс моего приложения. В частности, я запускаю gui, завернутый в класс, и это внутри процесса, и я пытаюсь отправить сообщения из gui в основной процесс через канал.pyobjc как подпроцесс, связанный с основным процессом через трубу, не работает
Когда я использую простой метод для ввода данных в трубу, мой код работает. Сообщение переходит к основному процессу, давая main process... recv(): foo
Когда я запускаю gui в подпроцессе и пытаюсь поместить данные в трубу, скажите, когда я нажимаю на пункт меню «start», ничего не происходит. Основная технологическая линия никогда не печатается, и насколько я могу судить, основной процесс заблокирован.
Я предполагаю, что это имеет какое-то отношение к циклу событий в pyobjc. Что я могу сделать, чтобы сделать эту работу? Как я могу запустить код pyobjc в качестве подпроцесса?
main.py
import sys
from multiprocessing import Process, Pipe
from userinterface import OSXstatusbaritem
def f2(pipe):
print "starting subprocess f2"
print pipe.send("foo")
pipe.close()
def main():
pipeUI, pipeServer = Pipe()
# p = Process(target=f2, args=(pipeUI,)) # <---------------------- This works
p = Process(target=OSXstatusbaritem.start(pipeUI), args=()) # <----This doesn't
p.start()
print "main process... recv():", pipeServer.recv()
p.join()
if __name__ == "__main__": sys.exit(main())
userinterface.py
import objc, re, os
from Foundation import *
from AppKit import *
from PyObjCTools import AppHelper
from multiprocessing import Pipe
status_images = {'idle':'./ghost.png'}
class OSXstatusbaritem(NSObject):
images = {}
statusbar = None
state = 'idle'
@classmethod
def start(self, pipe):
self.pipe = pipe
self.start_time = NSDate.date()
app = NSApplication.sharedApplication()
delegate = self.alloc().init()
app.setDelegate_(delegate)
AppHelper.runEventLoop()
def applicationDidFinishLaunching_(self, notification):
statusbar = NSStatusBar.systemStatusBar()
# Create the statusbar item
self.statusitem = statusbar.statusItemWithLength_(NSVariableStatusItemLength)
# Load all images
for i in status_images.keys():
self.images[i] = NSImage.alloc().initByReferencingFile_(status_images[i])
# Set initial image
self.statusitem.setImage_(self.images['idle'])
# self.statusitem.setAlternateImage_(self.images['highlight'])
# Let it highlight upon clicking
self.statusitem.setHighlightMode_(1)
# Set a tooltip
self.statusitem.setToolTip_('Sample app')
# Build a very simple menu
self.menu = NSMenu.alloc().init()
# Start and stop service
menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Start Service', 'startService:', '')
self.menu.addItem_(menuitem)
menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Stop Service', 'stopService:', '')
self.menu.addItem_(menuitem)
# Add a separator
menuitem = NSMenuItem.separatorItem()
self.menu.addItem_(menuitem)
# Terminate event
menuitem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Quit', 'terminate:', '')
self.menu.addItem_(menuitem)
# Bind it to the status item
self.statusitem.setMenu_(self.menu)
# Get the timer going
self.timer = NSTimer.alloc().initWithFireDate_interval_target_selector_userInfo_repeats_(self.start_time, 5.0, self, 'tick:', None, True)
NSRunLoop.currentRunLoop().addTimer_forMode_(self.timer, NSDefaultRunLoopMode)
self.timer.fire()
def tick_(self, notification):
print self.state
def startService_(self, notification):
self.pipe.send(["foobar", None])
print "starting service"
def stopService_(self, notification):
print "stopping service"
Чтобы уточнить, что безопасный способ запуска элемента статуса в качестве подпроцесса означает использование модуля 'subprocess' или использование' os.fork + os.exec'? Каков типичный способ сделать IPC между процессами в этом случае? Просто стандартная труба Unix? – nflacco
Будет работать либо os.fork + os.exec, либо модуль подпроцесса. Я бы использовал модуль подпроцесса, потому что h был более приятным интерфейсом. Затем вы должны использовать каналы для связи (аргумент subprocess.PIPE для STDOUT или os.pipe, если вы не используете модуль подпроцесса). –