Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 除了调用thread.Join()之外,我如何等待线程完成运行?_C#_Multithreading_C# 3.0 - Fatal编程技术网

C# 除了调用thread.Join()之外,我如何等待线程完成运行?

C# 除了调用thread.Join()之外,我如何等待线程完成运行?,c#,multithreading,c#-3.0,C#,Multithreading,C# 3.0,我正在从事一个项目,在这个项目中,这些方法是从库中提供的应用程序中调用的 我的按钮单击事件中有以下代码: Thread thread = new Thread(new ThreadStart(AddPics)); thread.Priority = ThreadPriority.Highest; thread.Start(); execute(); 但是,在运行示例时,执行点总是移动到execute。如何使程序首先执行AddPics方法。我已经尝试了thread.Join(),它成功了,但我想

我正在从事一个项目,在这个项目中,这些方法是从库中提供的应用程序中调用的

我的按钮单击事件中有以下代码:

Thread thread = new Thread(new ThreadStart(AddPics));
thread.Priority = ThreadPriority.Highest;
thread.Start();
execute();

但是,在运行示例时,执行点总是移动到execute。如何使程序首先执行
AddPics
方法。我已经尝试了
thread.Join()
,它成功了,但我想知道是否还有其他方法可以实现这一点。

您可以使用
Join
AutoResetEvent
等待添加图片线程完成,但您不应该使用这两种方法,正如后面的答案所述。

您可以使用
AutoResetEvent
作为
Join
的替代方法来获得相同的结果;它允许您设置阻止通知,因此在调用
execute()
方法之前阻止,并且仅当
AddPics
线程完成其作业时才继续:

private AutoResetEvent _finishAddPicsNotifier = new AutoResetEvent(false);

private void OnMyButton_Click(object sender, EventArgs e)
{
    //.....
    new Thread(AddPics)
    {
        Priority = ThreadPriority.Highest,
        IsBackground = true, //will explain later
    }.Start();

    _finishAddPicsNotifier.WaitOne();//this will block until receive a signal to proceed
    execute();//this method will only be called after the AddPics method finished
    /.....
}

private void AddPics()
{
    try{
        //.......
    }
    finally{
        _finishAddPicsNotifier.Set();//when finished adding the pictures, allow the waiting method to proceed
    }
}
注意:设置
IsBackground=true
表示线程是后台线程,因此不会阻止应用程序终止。阅读更多关于后台线程的信息

问题:

  • 由于您使用的是单击按钮来运行线程,因此应该添加一些机制来防止同时多次单击以多次运行代码
  • 调用
    Join()
    \u finishadpicsniffer.WaitOne()
    时,也会阻塞UI线程
要解决所有这些问题,一个好的设计是定义一个方法
OnFinishAddingPictures
并在完成添加图像时调用它,在这个新方法调用
execute()
,您还应该从按钮单击中删除以前的
execute()
调用:

private readonly object _oneAddPicturesLocker = new object();

private void OnMyButton_Click(object sender, EventArgs e)
{
    //.....
    new Thread(AddPics)
    {
        Priority = ThreadPriority.Highest,
        IsBackground = true,
    }.Start();
}

private void AddPics()
{
    if (Monitor.TryEnter(_oneAddPicturesLocker))
    {
        //we only can proceed if no other AddPics are running.
        try
        {
            //.....

            OnFinishAddingPictures();
        }
        finally
        {
            Monitor.Exit(_oneAddPicturesLocker);
        }
    }
}

private void OnFinishAddingPictures()
{
    execute();
}
注意:

  • 我们使用这种机制消除了阻塞
  • 我们确信一次只能执行一个对
    AddPics
    的调用
  • 无论何时从不是UI线程的线程访问表单或控件方法和属性,请始终记住选中
    invokererequired
    并使用
    control.Invoke(/*..*/)

我假设您的主要目标是在运行带有
AddPics
的线程时拥有响应式UI?如果是,那么您可以对WinForms使用以下构造:

while (thread.IsAlive)
    System.Windows.Forms.Application.DoEvents();

如果要暂停直到线程完成,为什么不直接调用
AddPics
-为什么要使用线程?能否告诉我们为什么不使用线程。Join()?这可能有助于明确您的意图,并将产生更好的答案。使用
Application.DoEvents
是个坏主意,它产生的问题比解决的问题多。调用“DoEvents()”只能在复杂的应用程序中导致问题。但是,如果某个人有头脑,那么“做的事”可以起到善的作用,而不是恶的作用:)它总是坏的,因为你把它写在那里,并伪造它。一个例子是你的程序和每件事都很好,6个月后,一个新的场景即将出现,你希望在计算机时间改变时得到通知“例如”你通过收听windows消息轮询来做到这一点。。运行应用程序并对其进行测试,一切都很好。。但是等一下,我们忘记了
应用程序。DoEvents()
,它隐藏在代码中的某个地方,因此如果在
应用程序运行时收到消息,您的应用程序将不会收到通知。DoEvent()
“6个月后…”==“复杂应用程序”@Lokesh:您尝试过这种方法吗,它是否满足您的需要?