我发现至少为 Mac 编写一些具有或多或少常见 UI 的东西是很困难的。我的应用程序必须有 tray icon 并且能够显示 system notifications

问题是 goroutine 本身。在 Mac 上对 UI 框架的任何调用都要求从主线程调用,或者至少以线程安全的方式调用。

当我已经在运行 UI(嗯,对于 GUI 应用程序是必须的,不是吗?)并尝试显示通知时,就会出现问题。原因似乎是 systray 包 Init 函数必须使用 runtime.LockOsThread 锁定到主线程并且永远不会释放它。然后,如果我尝试显示也需要 runtime.LockOsThread 的通知,则会导致以下错误:

2016-01-11 22:56:27.973 main[30162:4094392] *** Assertion failure in +[NSUndoManager _endTopLevelGroupings], /Library/Caches/com.apple.xbs/Sources/Foundation/Foundation-1256.1/Misc.subproj/NSUndoManager.m:359
2016-01-11 22:56:27.974 main[30162:4094392] +[NSUndoManager(NSInternal) _endTopLevelGroupings] is only safe to invoke on the main thread.
2016-01-11 22:56:27.977 main[30162:4094392] (
    0   CoreFoundation                      0x00007fff8d42bae2 __exceptionPreprocess + 178
    1   libobjc.A.dylib                     0x00007fff8bb03f7e objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff8d42b8ba +[NSException raise:format:arguments:] + 106
    3   Foundation                          0x00007fff8cb4c88c -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 198
    4   Foundation                          0x00007fff8cad24c1 +[NSUndoManager(NSPrivate) _endTopLevelGroupings] + 170
    5   AppKit                              0x00007fff8514206a -[NSApplication run] + 844
    6   main                                0x0000000004166200 nativeLoop + 128
    7   main                                0x0000000004165bca _cgo_8c6479959095_Cfunc_nativeLoop + 26
    8   main                                0x000000000405a590 runtime.asmcgocall + 112
)
2016-01-11 22:56:27.977 main[30162:4094392] *** Assertion failure in +[NSUndoManager _endTopLevelGroupings], /Library/Caches/com.apple.xbs/Sources/Foundation/Foundation-1256.1/Misc.subproj/NSUndoManager.m:359
2016-01-11 22:56:27.978 main[30162:4094392] An uncaught exception was raised
2016-01-11 22:56:27.978 main[30162:4094392] +[NSUndoManager(NSInternal) _endTopLevelGroupings] is only safe to invoke on the main thread.

有解决方法吗?到目前为止我能想到的就是将 UI 和通知放入单独的二进制文件中,并使它们通过某种 IPC 与 main 进行通信。但我可能会遗漏一些东西。

最佳答案

由于这个问题没有足够的吸引力,我决定发布我在尝试解决此问题时发现的自己的解决方案。这不会被标记为答案,因为其他人可能会提供更好的解决方案。

我已将一个 UI 进程(即使用 systray 的部分)移动到另一个二进制文件中,并使用 cmd := exec.Command(...)cmd.Start() 调用它,然后我通过管道传输 stdinstdout 并通过它们与这个子进程通信。

示例代码可以在 Github 上找到。 警告 在这个要点中有一个错误,子进程退出后主进程将开始消耗 CPU 周期。随意自己修复它。

我不想使用 RPC 的原因是因为这对于我想要实现的目标来说会变得有点过于复杂,并且没有提供简单的方法来进行双向通信。

关于multithreading - 继续 OS X - 两个库调用系统函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34724912/

10-14 14:43
查看更多