【发布时间】:2020-07-02 06:36:50
【问题描述】:
这是一个基于 .net 4.7.2 的 WPF 项目。
为了重新启动一个进程(不是主进程本身,而是由主进程启动的其他进程),在进程的退出事件处理程序中调用process.Start()。
简化代码如下:
public MainWindow()
{
InitializeComponent();
Process process = new Process()
{
StartInfo =
{
FileName = *<path to a bat file>*,
WorkingDirectory = *<folder to the bat file>*,
UseShellExecute = true,
},
EnableRaisingEvents = true,
};
// register handler
process.Exited += (sender, args) =>
{
Dispatcher.Invoke(() =>
{
process.Start(); // restart after be killed
});
Console.Out.WriteLine("OnExit Finish");
};
// start for the first time
process.Start();
// wait and kill
Thread.sleep(2000);
process.CloseMainWindow();
process.Kill();
}
问题是Dispatcher中的Start()。进程重启后Invoke没有返回,这意味着卡住了。 挖掘后发现了一些东西,但仍然无法通过。
- 它挂在进程中的锁上:
此方法来自donet框架源码。它是通过多个以 Process.Start() 为根的调用来调用的。
The whole file can be found here
private void EnsureWatchingForExit()
{
if (this.watchingForExit)
return;
lock (this) // ***** IT HANGS *****
{
if (this.watchingForExit)
return;
this.watchingForExit = true;
try
{
this.waitHandle = (WaitHandle) new ProcessWaitHandle(this.m_processHandle);
this.registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(this.waitHandle, new WaitOrTimerCallback(this.CompletionCallback), (object) null, -1, true);
}
catch
{
this.watchingForExit = false;
throw;
}
}
}
- 使用 Dispatcher.InvokeAsync() 代替 Invoke() 可以解决挂起问题。
lock block 在 C# 中是 Monitor.Enter() 的缩写,它是可重入的。并且 Invoke() 保证它与运行到锁的线程相同。
我很好奇为什么会卡住?
【问题讨论】:
-
lock(this)是不好的做法,this引用可以在外部更改 -
这能回答你的问题吗? Best Practices in using a lock
-
@PavelAnikhouski 可能不是。 EnsureWatchingForExit 代码段不是我编写的。来自donet框架源代码。
-
我敢冒险重用现有的
Process实例可能是个坏主意。如果您丢弃旧的Process实例并启动一个新实例而不是重复使用会发生什么? -
@Mufaka 还是不行:(
标签: c# wpf multithreading