怎么判断定线程执行完了?

游戏人间 2013-02-18 05:35:22
下面这段代码怎么才能保证线程执行完了,主线程再执行,请测试通过了再说。
因为这个比较特殊,线程中要访问控件,就使得次程要切换到主线访问控件。所以
使用 thread.Join(), ManualResetEvent 等方法 都会使程序死掉。


一个Form 窗体,btnTest 按钮 txtMsg文本框

  public partial class Form1 : Form
{

Thread thread;

public Form1()
{
InitializeComponent();
}

private void btnTest_Click(object sender, EventArgs e)
{

thread = new Thread(new ThreadStart(DoWork));
thread.Start();

//......

txtMsg.Text = "完成";

}

void DoWork()
{
SetText("线程运了。");

}

delegate void SetTextHandler(string msg);
private void SetText(string msg)
{
if (txtMsg.InvokeRequired)
{
SetTextHandler d = new SetTextHandler(SetText);
object val = (object)msg;
this.Invoke(d, val);
}
else
{
txtMsg.Text += "\r\n" + msg;
}
}
}
...全文
15214 52 打赏 收藏 转发到动态 举报
写回复
用AI写文章
52 条回复
切换为时间正序
请发表友善的回复…
发表回复
willhuo 2014-04-04
  • 打赏
  • 举报
回复
用哪个backgrouworker不是更简单吗,里边加上多线程和委托
armstrongw 2014-03-07
  • 打赏
  • 举报
回复
ManualResetEvent raserEvent = new ManualResetEvent(false); Thread test1 = new Thread( new ThreadStart( () => { new AV().test(); //xxxx.fff //方法 raserEvent.Set(); } ) ); test1.Start(); Thread test2 = new Thread( new ThreadStart( () => { if (raserEvent.WaitOne()) { Console.WriteLine("123"); this.Dispatcher.Invoke( new Action( () => { this.lb.Content = "1234"; })); } } ) ); test2.Start(); }
wtoeb 2013-06-24
  • 打赏
  • 举报
回复
妈的,中国人就是喜欢绕?还是过于愚蠢?一个简单的问题,搞得这么复杂。。。
人生初见 2013-06-01
  • 打赏
  • 举报
回复
标记下,改天研究
dreamgis 2013-03-03
  • 打赏
  • 举报
回复
先标记,改天再看,线程的东西是个难点
showjim 2013-02-26
  • 打赏
  • 举报
回复
引用 44 楼 wonderfuly 的回复:
现在的做法就中在Test()调用时采用一个线程调用, 之前的Join . WaitHandle.WaitAll两方案都可以完美运行。
汗!原来你不需要阻塞UI,仅仅需要等待线程结束,那uiWait就不符合你的需求。 早说清楚,应该就不会有一些人误会了,只需要在非UI线程中using(fastCSharp.threading.task)就可以了
using(fastCSharp.threading.task task = new fastCSharp.threading.task(2))
{
    task.Add(DoWork);
    task.Add(DoWork);
}
InvokeText("完成");
duxuebin0124 2013-02-26
  • 打赏
  • 举报
回复
卖关子、、、 无趣 学习中、、、
showjim 2013-02-25
  • 打赏
  • 举报
回复
我提供的uiWait子线程是可并行的,而且UI操作既可以同步也可以异步,不会等到最后一起执行,也不需要Invoke。
            fastCSharp.threading.task task = new fastCSharp.threading.task(2);//非UI线程任务,最大并行2线程
            task.Add(DoWork);
            task.Add(DoWork);
            uiWait = new uiWait(task);

            //第一种UI线程方式,这里应该使用第一种
            uiWait.Wait();

            //第二种子线程方式,非UI类似同步需求扩展
            uiWait.RunThread();
            //do something
            uiWait.WaitThread();

            txtMsg.Text = "完成";
        void DoWork()
        {
            //第一种同步模式
            uiWait.AddWait(() => txtMsg.Text = "线程开始了。");
            //do something
            uiWait.AddWait(() => txtMsg.Text = "线程结束了。");

            //第一种异步模式
            uiWait.Add(() => txtMsg.Text = "线程开始了。");
            //do something
            uiWait.Add(() => txtMsg.Text = "线程结束了。");
        }
游戏人间 2013-02-25
  • 打赏
  • 举报
回复
感谢各位的参与, 重点感谢 "lye2000000_super" 说一下“lye2000000_super”提供的完整的例子存在的一些问题。 1、虽然程序没有卡死,但是所有信息都是等到最后一起输出来的。线程执行的时候,UI假死了。 2、信息输出的顺序不对。 程序之所以加个WaitHandle.WaitAll 或 Join 等之类就是希望输出的顺序是: 线程xxx运行了,最后才是任务完成。 而不是一开始就任务完成了,再输入线程xxx运行了等信息。 今天还测试了一下合着与分开的区别。 还有就是Invoke 与 BeginInvoke 。BeginInvoke是异步调用。 Invoke还是卡死。 采用BeginInvoke 虽然程序不会卡死,但UI会假死。 还有就是合着写顺序错误,分开写顺序正确。 sbwwkmyd 提供的参考就没仔细测试了,看着有点复杂。


        void SetText(string msg)
        {
            if (txtMsg.InvokeRequired)
            {
                SetTextHanlder d = new SetTextHanlder(SetText);
                object o = (object)msg;
                this.Invoke(d, msg);
            }
            else
            {
                txtMsg.Text = msg + "\r\n" + txtMsg.Text;
            }
           
        }



        private void InvokeText(string msg)
       {
            txtMsg.Invoke(new SetTextHanlder(SetText), new object[] { obj });
       
        }
        private void SetText(string msg)
        {
            txtMsg.Text = "\r\n" + msg + txtMsg.Text;
        }
其实我已经有角决方案了。 如果有高手看到的话请继续探讨。 现在的做法就中在Test()调用时采用一个线程调用, 之前的Join . WaitHandle.WaitAll两方案都可以完美运行。
            Thread thread = new Thread(new ThreadStart(Test));
            thread.Start();
其它 sbwwkmyd提供的完整便跟第二个例差不多, 区别就是 SetText 分开写,还有就是 Invoke 采用一异步也就是BeginInvoke UI假死和顺序不对他这个程序的缺点。
ERROR已经存在 2013-02-23
  • 打赏
  • 举报
回复
引用 25 楼 wonderfuly 的回复:
再一个 ManualResetEvent WaitHandle.WaitAll 版的吧免一些人 在那说这说那。 程序加上这个 WaitHandle.WaitAll(doneEvents);就会卡死。 C# code?12345678910111213141516171819202122232425262728293031323334353637383940414……
当然卡死,主线程WaitALL中,不会有其他相应的
wwwww112233 2013-02-22
  • 打赏
  • 举报
回复
Callback回调 或task.waitall
kmblack1 2013-02-22
  • 打赏
  • 举报
回复
补充:ISynchronizeInvoke接口在Form中已经实现
kmblack1 2013-02-22
  • 打赏
  • 举报
回复
1.每次点击button都创建一个线程的话太浪费资源,最好在程序启动时就创建一个后台线程,在程序退出时关闭后台线程,线程在没任务时休眠,有任务时唤醒线程执行任务 2.等待线程结束用Join()方法,但是如果线程正在执行任务的话会出现界面卡死的情况,所以线程中执行的方法应该支持取消功能 3.线程和窗体交互使用事件,但是不能直接在线程的方法里触发事件,应使用ISynchronizeInvoke::BeginInvoke方法调用委托,确保事件在主线程中执行; demo: http://blog.csdn.net/kmblack1/article/details/8348662
showjim 2013-02-22
  • 打赏
  • 举报
回复
引用 34 楼 zhang_7150 的回复:
UI的设计果然是很神奇的东东
这个实现得太简单,虽然可行,但是没法做同步操作。 另外Thread.Sleep(3000);这个不是UI操作,除非必要不应该放在Run里面。
Kilin_Zhang 2013-02-22
  • 打赏
  • 举报
回复
引用 32 楼 sbwwkmyd 的回复:
当然出现这种情况也是有解的: 如果需要在任务完成之前阻塞UI线程,一个非UI线程就应该直接调用。 多个非UI线程的话需要实现一个UI任务队列,非UI线程不应该直接操作UI,UI线程Wait任务……
类似于下面这种?

private event Action Run;
        private void btnTest_Click(object sender, EventArgs e)
        {
            Task task = new Task(() =>
            {
                Run += () =>
                {
                    txtMsg.Text = "线程开始运行了";
                    Thread.Sleep(3000);
                };
            });
            task.Start();
            task.Wait();

            Run += () =>
            {
                txtMsg.Text = "线程运行完成";
            };

            Run();
        }
UI的设计果然是很神奇的东东
  • 打赏
  • 举报
回复
支持楼主,有时涉及到的问题3#方法不定适用.
showjim 2013-02-22
  • 打赏
  • 举报
回复
引用 29 楼 zhang_7150 的回复:
如此说来,楼主的要的效果不是不能实现了。
一般情况下就不要设计这样的程序流程,UI操作与非UI操作分离就不会出现这种情况。 当然出现这种情况也是有解的: 如果需要在任务完成之前阻塞UI线程,一个非UI线程就应该直接调用。 多个非UI线程的话需要实现一个UI任务队列,非UI线程不应该直接操作UI,UI线程Wait任务队列,非UI线程往队列里面添加任务就可以了。
  • 打赏
  • 举报
回复
引用 25 楼 wonderfuly 的回复:
再一个 ManualResetEvent WaitHandle.WaitAll 版的吧免一些人 在那说这说那。 程序加上这个 WaitHandle.WaitAll(doneEvents);就会卡死。 C# code?12345678910111213141516171819202122232425262728293031323334353637383940414……
你这个卡死的不是ManualResetEvent ,是 delegate void SetTextHandler(string msg); private void SetText(string msg) { if (txtMsg.InvokeRequired) { SetTextHandler d = new SetTextHandler(SetText); object val = (object)msg; this.Invoke(d, val); } else { txtMsg.Text += "\r\n" + msg; } } 这里卡死了。
  • 打赏
  • 举报
回复
public Form8() { InitializeComponent(); } Thread thread1, thread2; Object obj = new object(); List<ManualResetEvent> mres = new List<ManualResetEvent>(); Task task = new Task(); private void button1_Click(object sender, EventArgs e) { richTextBox1.Text = ""; Test(); } public void Test() { task.OnMessageNotice += invokeMsg; ManualResetEvent mre1 = new ManualResetEvent(false); mres.Add(mre1); ManualResetEvent mre2 = new ManualResetEvent(false); mres.Add(mre2); thread1 = new Thread(new ParameterizedThreadStart(task.DoWork)); thread2 = new Thread(new ParameterizedThreadStart(task.DoWork)); DataCls data1 = new DataCls(1, mre1); DataCls data2 = new DataCls(2, mre2); thread1.Start(data1); thread2.Start(data2); WaitHandle.WaitAll(mres.ToArray()); lock (obj) { richTextBox1.AppendText("任务已完成"); } } public delegate void SetTextHanlder(string msg); private void invokeMsg(String obj){ if (richTextBox1.InvokeRequired) { richTextBox1.BeginInvoke(new SetTextHanlder(SetText), new object[] { obj }); } } private void SetText(string msg) { lock (obj) { richTextBox1.AppendText("\r\n" + msg); } //} } private void DoWork(object obj) { Invoke(new SetTextHanlder(SetText), new object[] { obj }); } } //消通知委托 public delegate void MessageNotice(string msg); //任务类 public class Task { public event MessageNotice OnMessageNotice; public void DoWork(object state) { DataCls data = state as DataCls; MessageNoticeHandler(string.Format("每{0}个任务正在执行......", data.count)); //执行任务 具体任务就不写了用sleep代表任务要用很长时间。 Thread.Sleep(3000); MessageNoticeHandler(string.Format("每{0}个任务执行完成", data.count)); data.m_mre.Set(); } protected void MessageNoticeHandler(string msg) { if (OnMessageNotice != null) { OnMessageNotice(msg); } } } public class DataCls { public ManualResetEvent m_mre; public int count; public DataCls(int i,ManualResetEvent mre) { count = i; m_mre = mre; } } 贴个完整的吧。 死的原因知道了。那个invoke调用的不对。调到那就死了。。。。 没反应的。这个是可以实现的。楼主自己试一下吧。
Kilin_Zhang 2013-02-22
  • 打赏
  • 举报
回复
引用 17 楼 sbwwkmyd 的回复:
引用 16 楼 zhang_7150 的回复:经过实际测试, this.Invoke貌似要等回族线程运行完成后才执行。不解 因为UI线程的任务是队列模式的,前一个UI任务不执行完,后一个就会等着,相互等着对方就死锁了。
如此说来,楼主的要的效果不是不能实现了。
加载更多回复(31)

110,537

社区成员

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

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

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