两个线程之间的交互

时间:2011-09-02 15:49:31

标签: c# multithreading

我正在开发一个winform应用程序,我的目标是让我的表单上的标签对用户可见,三秒钟之后使标签不可见。这里的问题是超时三秒。老实说,我不知道这是否是我问题的正确解决方案,但我能够通过创建一个新线程并使新线程休眠三秒钟来完成这项工作(System.Threading.Thread.Sleep(3000))

我无法使用System.Threading.Thread.Sleep(3000)因为这会冻结我的GUI 3秒!

private void someVoid()
{
     lbl_authenticationProcess.Text = "Credentials have been verified authentic...";

     Thread sleepThreadStart = new Thread(new ThreadStart(newThread_restProgram));
     sleepThreadStart.Start();

     // Once three seconds has passed / thread has finished: lbl_authenticationProcess.Visible = false;
}

private void newThread_restProgram()
{
     System.Threading.Thread.Sleep(3000);
}

所以,回到我原来的问题。如何(从我的主线程)确定新线程何时完成,意味着已经过了三秒钟?

我对新想法持开放态度,并且我确信有很多想法。

8 个答案:

答案 0 :(得分:5)

现在,您正在阻止整个UI线程,以便在3秒后隐藏标签。如果这是你想要的,那么只需从表单中的用户Thread.Sleep(3000)。如果没有,那么你最好使用Timer

System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 3000;
timer.Tick += (s, e) => { this.lbl_authenticationProcess.Visible = false; timer.Stop(); }
timer.Start();

3秒后,标签将消失。但是,在您等待时,用户仍然可以与您的应用程序进行交互。

请注意,必须使用Timer的Forms版本,因为它在UI线程上引发了Tick事件,允许直接访问控件。其他计时器可以工作,但与控件的交互必须是Invoke/BeginInvoke d。

答案 1 :(得分:2)

您是否尝试使用计时器

System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 3000;
t.Start();
t.Tick += new EventHandler(t_Tick);

void t_Tick(object sender, EventArgs e)
{
     label.Visible = false;
}

答案 2 :(得分:2)

你真的不需要同步任何东西。您只需要一个新线程,并引用您的标签。你的代码实际上非常接近:

private void someVoid()
{
     lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
     lbl_authenticationProcess.Visible = true;

     Thread sleepThreadStart = new Thread(new ThreadStart(newThread_restProgram));
     sleepThreadStart.Start();
}

private void newThread_restProgram()
{
     System.Threading.Thread.Sleep(3000);
     if (lbl_authenticationProcess.InvokeRequired) {
         lbl_authenticationProcess.Invoke(new SimpleCallBack(makeInvisible));
     } else {
         makeInvisible();
     }
}

private void makeInvisible()
{
     lbl_authenticationProcess.Visible = false;
}

因此,当调用someVoid()时,会设置标签上的消息,使标签可见。然后以newThread_restProgram()作为正文启动新线程。新线程将休眠3秒钟(允许程序的其他部分运行),然后睡眠结束,标签变为不可见。新线程自动结束,因为它的body方法返回。

答案 3 :(得分:1)

您可以制作一个类似的方法:

public void SetLbl(string txt)
{
 Invoke((Action)(lbl_authenticationProcess.Text = txt));
}

你可以从第二个线程调用它,但它会在主线程上调用。

答案 4 :(得分:1)

如果你使用的是.NET 3.5或更早版本,那就太痛苦了:

 private void YourMethod()
 {
      someLabel.BeginInvoke(() =>
         {
              someLabel.Text = "Something Else";

              Thread thread = new Thread(() =>
                 {
                       Thread.Sleep(3000);
                       someLabel.BeginInvoke(() => { someLabel.Visible = false; });
                 });

              thread.Start();
         });
 }

这应该阻止你阻止UI。

如果您使用的是.NET 4 +:

Task.Factory.StartNew(() =>
     {
           someLabel.BeginInvoke(() => { someLabel.Text = "Something" });
     }).ContinueWith(() =>
     {
         Thread.Sleep(3000);
         someLabel.BeginInvoke(() => { someLabel.Visible = false; });
     });

答案 5 :(得分:1)

如果您愿意下载Async CTP,那么您可以使用这个非常优雅的解决方案,该解决方案需要新的asyncawait关键字。 1

private void async YourButton_Click(object sender, EventArgs args)
{
   // Do authentication stuff here.
   lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
   await Task.Delay(3000); // TaskEx.Delay in CTP
   lbl_authenticationProcess.Visible = false;
}

1 请注意,异步CTP使用TaskEx代替Task

答案 6 :(得分:0)

您可以使用AutoResetEvent进行线程同步。您将事件设置为在辅助线程从其睡眠状态唤醒时发出信号,以便它可以通知您的主线程。

这意味着你的主线程等待另一个线程完成。

在该注释中,您可以使用SecondThread.Join()等待它在主线程中完成。

您执行上述 ,但您不需要同时执行这两项操作。

正如评论中所建议的,拥有UI线程睡眠通常不是一个好主意,因为它会导致用户无法响应。

但是如果你这样做,你可能只是睡觉主线程并摆脱第二线程的无关需要。

答案 7 :(得分:0)

我不确定这是正确的方法,但要回答你的问题,你必须使用Join()函数。

public void CallingThread()
{
    Thread t = new Thread(myWorkerThread);
    t.Join();
}

public void WorkerThread()
{
    //Do some stuff
}

您还可以将超时作为参数添加到函数中,但这里不需要它。