今天我在开发的应用程序中遇到了死锁问题。 特别是我正在停止一个Window,它在后台启动了一个Thread。
问题?关闭窗口窗口关闭,但进程在后台仍然存在。 我想过如果Thread本身阻塞,但作为Background声明的Thread,它应该正常关闭。 但后来我注意到“Logic.DoSomething()”启动了它自己的无尽线程,而没有将它声明为Background-Threads。
那么为什么(背景)线程中的(非背景)线程阻塞进程呢?它不应该关闭,因为它的“父”运行为Background-Thread? 如果没有,为什么不阻止Parent-Thread本身呢?
public partial class MainWindow : Window
{
private Thread TheThread { get; set; }
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
Closed += MainWindow_Closed;
}
private void MainWindow_Loaded(object sender, EventArgs e)
{
// Create the (background-)thread and start it
TheThread = new Thread(() => Logic.DoSomething());
TheThread.IsBackground = true;
TheThread.Start();
}
private void MainWindow_Closed(object sender, EventArgs e)
{
// Close Thread if existent.
TheThread.Abort("Window was closed");
TheThread.Join(500);
}
}
PS:请注意,我不使用Worker-Object,因为我在线程中正常处理Abort-Exception。
编辑:这是Windows Presentation Foundation-Project(WPF)的理论问题,而不是Windows窗体项目。 除此之外,基本问题不是如何使用例如启动和停止线程。的CancellationToken。这是一个问题,为什么一个进程创建的一个线程不会杀死它调用的进程或者在加入时被卡住。 希望这很清楚。
答案 0 :(得分:2)
而不是在线程上调用Abort
,这绝不是一个好主意,而是与线程通信并指示它应该停止。然后等待线程停止。沟通这种事情的好方法是等待句柄。在以下示例中,我将使用ManualResetEvent
:
public partial class MainWindow : Window
{
private ManualResetEvent theThreadShouldStop;
private Thread TheThread { get; set; }
public MainWindow()
{
InitializeComponent();
// ??? This should be set through designer!!
Loaded += MainWindow_Loaded;
Closed += MainWindow_Closed;
theThreadShouldStop = new ManualResetEvent(false);
}
private void MainWindow_Loaded(object sender, EventArgs e)
{
// Create the (background-)thread and start it
TheThread = new Thread(() => Logic.DoSomething(theThreadShouldStop));
TheThread.IsBackground = true;
TheThread.Start();
}
private void MainWindow_Closed(object sender, EventArgs e)
{
// Close Thread if existent.
theThreadShouldStop.Set();
TheThread.Join();
theThreadShouldStop.Close();
}
}
现在线程方法需要合作,但由于我不知道线程方法的作用,我将给出一个常见场景的示例,其中线程在一个应该可以取消的循环中运行:
public class Logic
{
public void DoSomething(ManualResetEvent cancel)
{
while (!WantHandle.WaitOne(cancel, 1))
{
... Do stuff
}
}
}
答案 1 :(得分:1)
主题没有“父母”。没有等级。他们不知道或不关心什么线程启动它们。它们只是线程,当没有运行非后台线程时应用程序结束;这里的所有都是它的。线程阻塞,直到另一个线程通过调用Join
要求 结束。他们不会在没有你告诉他们的情况下自己做事。他们完全按照你告诉他们的方式行事。