在自己创建的Thread当中Sleep,发现会让主线程也卡住,为什么?

qweroio 2014-08-17 01:41:41
我在一个winform的main函数中,自己创建了一个线程。这个线程先睡16秒,然后通过BeginInvoke去修改textBox1.Text。代码如下所示:

public partial class Form1 : Form
{
public delegate void InvokeDelegate();
private void Invoke_Click(object sender)
{
textBox1.BeginInvoke(new InvokeDelegate(InvokeMethod));
}
public void InvokeMethod()
{
Thread.Sleep(16000);
textBox1.Text = "Executed the given delegate";
}

public Form1()
{
InitializeComponent();
var thread = new Thread(new ParameterizedThreadStart(Invoke_Click), 2048000);
thread.Start();
}
}

我期待的结果是,主界面启动以后,所有控件都能显示。过了16秒,textBox1控件中的内容变成"Executed the given delegate"
但是实际的结果是
(1)程序启动以后变成左边的样子,一直没有响应长达16秒,界面上什么文字都显示不出来。如左图
(2)16秒以后变成右图的模样。

为什么不合我的预期呢,我对Thread/BeginInvoke的理解都不对吗?
...全文
1881 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
devmiao 2014-08-17
  • 打赏
  • 举报
回复
简单来说,Invoke中的代码,在UI线程执行,相当于单线程,这也是为什么UI更新操作要放在Invoke中同步才不会出错的根本原因。
  • 打赏
  • 举报
回复
如果要修改,就是改动一行代码
        private void Invoke_Click(object sender)
        {
            Thread.Sleep(16000);
            textBox1.BeginInvoke(new InvokeDelegate(InvokeMethod));
        }
        public void InvokeMethod()
        {
            textBox1.Text = "Executed the given delegate";
        }
但是实际上滥用线程实在是没有必要。Timer是操作系统的中断控制的,是高效率的机制,触发事件之前只需要注册而不需要占用任何线程,不是你的线程可比的。
xian_wwq 2014-08-17
  • 打赏
  • 举报
回复

public class MyForm : System.Windows.Forms.Form {
            
    //UI 元素
    private Label lblStatus;
    
    private ProgressBar progressBar1;

    //Delegate
    private delegate void MyProgressEventsHandler(
        object sender, MyProgressEvents e);

    
     private void UpdateUI(object sender, MyProgressEvents e) {
        lblStatus.Text = e.Msg;
        myProgressControl.Value = e.PercentDone;
    }

   //ShowProgress 现在可以记录为可从任何线程调用的公共方法。
    public void ShowProgress(string msg, int percentDone) 
   {
	if(InvokeRequired)
	{
	   System.EventArgs e = new MyProgressEvents(msg, percentDone);
           object[] pList = { this, e };

           BeginInvoke(new MyProgressEventsHandler(UpdateUI), pList);
	}
	else
        {
	    UpdateUI(this, new MyProgressEvents(msg,
            PercentDone)); 	
        }
       
    }

     private void btnStart_Click(object sender, EventArgs e)
     {
      //启动线程
      Thread t = new Thread(new ParameterizedThreadStart(RunsOnWorkerThread));
      t.IsBackground = true;
      t.Start(input);
     }

    //线程执行函数
    private void RunsOnWorkerThread() 
    {
        int i = 0;   
        while(...) //loop      
        {  
          DoSomethingSlow();
          ShowProgress("test",i);
          ++i;
        }
    }
   
}
这个例子没有用匿名函数和lambda表达式,好理解些
wjq 2014-08-17
  • 打赏
  • 举报
回复
你绕来绕去,最后用TextBox1.BeginInvoke来调用,还是回到由UI线程来执行代码……要搞多线程,要先考虑下实际的运用目的。只是学习的话,记住用UI对象的invoke方法就是让ui线程来执行实际操作。
xu56180825 2014-08-17
  • 打赏
  • 举报
回复
textBox1.BeginInvoke这句会将执行内容同步到GDI线程中去执行,所以主线程卡住
  • 打赏
  • 举报
回复
滥用线程你不担心吗? 你应该使用 Timer。

110,529

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧