• c# 子线程如何通知主线程,个人总结


    我要实现的功能如下:
    程序中有2个线程,主线程和子线程,
    主线程中有一个变量:X
    主线程运行中激活子线程,子线程会做出计算改变 X 的值,
    主线程继续做其它的事,直到 X 的值发生改变时,才会响应,并在textbox中输出 X 的值(这一过程中主线程并不知道何时X的值才会变,它不能循环等待,必须去做别的事,比如接收用户点击等等)。

    这个功能看起来简单,但是我始终找不到方法,我对委托和事件理解的还不透,不知道能不能用事件解决?
    期待各位高手解答。


    autoresetevent 试试


    将X封装成属性

    在Set里写入需要触发的代码不就可以了?不一定要主线程去做,子线程当然也可以做的。


    你这也是委托的问题,参考一下:

    C# code
    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    private void button1_Click(object sender, EventArgs e)
    {
        Thread th = new Thread(aa);
        th.Start();
    }
     
    delegate void somedle();
    private void aa()
    {
        if (this.InvokeRequired)
        {
            somedle sd = new somedle(aa);
            this.Invoke(sd);
            return;
        }
        ShowChar('A');
    }
    public void ShowChar(char ch)
    {
        lock (this)
        {
            textBox1.Text += ch;
        }
    }

      static void Main(string[] args)
            {
                ManualResetEvent myResetEvent = new ManualResetEvent(false);

                int X = 0;

                Thread childThread = new Thread(delegate()
                {
                    //Console.WriteLine(Thread.CurrentThread.Name + "  " + Thread.CurrentThread.ManagedThreadId);

                    Console.WriteLine("Set X Value");
                    X = 10;
                    Console.WriteLine("Set X Value end");

                    Console.WriteLine("Notice main thread");
                    myResetEvent.Set();
                });

                childThread.Start();

                while (true)
                {
                    if (myResetEvent.WaitOne())
                    {
                        Console.WriteLine("After child thread set X, X is " + X);
                        myResetEvent.Reset();
                    }
                }

                Console.ReadKey();
            }

    这里主要是ManualResetEvent的应用,和前面的兄弟提到的autoresetevent 是差不多的,区别自己看下msdn


    引用 2 楼 tmxk2002 的回复:
    将X封装成属性 

    在Set里写入需要触发的代码不就可以了?不一定要主线程去做,子线程当然也可以做的。


    推荐这种做法,封装一个事件,形如OnXChanged,主线程中注册此事件,事件触发时就会转到对应代码执行去了。

    当然,此时仍是在子线程中执行的。

    如一定要主线程去做事,考虑使用信号量、WatiHandle等线程同步机制吧


    引用 5 楼 agentianle 的回复:
    引用 2 楼 tmxk2002 的回复:
    将X封装成属性 

    在Set里写入需要触发的代码不就可以了?不一定要主线程去做,子线程当然也可以做的。 
     

    推荐这种做法,封装一个事件,形如OnXChanged,主线程中注册此事件,事件触发时就会转到对应代码执行去了。 

    当然,此时仍是在子线程中执行的。 

    如一定要主线程去做事,考虑使用信号量、WatiHandle等线程同步机制吧

    同意,实际上就是开放X的访问器。至于显示,简单点,还是不要让主线程去做的好。


    楼上说的我大概明白,但是我要在textbox中输出 X 的值必须由主线程完成,也就是说主线程是一个窗口类,它才能完成显示输出的功能,子线程只负责计算。
    4楼的代码:
      while (true) 
                { 
                    if (myResetEvent.WaitOne()) 
                    { 
                        Console.WriteLine("After child thread set X, X is " + X); 
                        myResetEvent.Reset(); 
                    } 
                } 

    这一段是否是要求主线程一直等待? 我的意思是主线程不能等待,还要去处理别的事,直到得到通知才去处理输出。


    可以用自带的BackgroundWorker控件来实现 动态创建它


    子线程可以操作界面的啊


    用就 
    Form.Invoke(Delegae d);
    这个方法就可以,你在子线程中改变检查到某个值时候通知主线程就可以了
    让改变发生在 参数d所指向的那个方法中就可以了;


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public delegate void SetIntValue(int value);
     
    public void setX(int value)
    {
        if (InvokeRequired)
        {
            // 在子线程中调用此方法时,通过Invoke转成主线程执行
            Invoke(new SetIntValue(value));
            return;
        }
     
        // 设置X值并显示
        X = value;
        textbox.Text = X.toString();
    }

    不好意思,刚才有点错误

    C# code?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public delegate void SetIntValue(int value);
     
    public void setX(int value)
    {
        if (InvokeRequired)
        {
            // 在子线程中调用此方法时,通过Invoke转成主线程执行
            <span style="color: #FF0000;">Invoke(new SetIntValue(setX), value);</span>
            return;
        }
     
        // 设置X值并显示
        X = value;
        textbox.Text = X.toString();
    }

    开启一个新的线程就行了,只要X的值发生改变,就激发一个事件,要自定义个事件


    引用 10 楼 projectdd 的回复:
    用就 
    Form.Invoke(Delegae d);
    这个方法就可以,你在子线程中改变检查到某个值时候通知主线程就可以了
    让改变发生在 参数d所指向的那个方法中就可以了;

    我也遇到类似问题,我的执行顺序是
    1.主线程 创建一个窗体mForm对象并Show();
    2.开启一个新的子线程,子线程指向循环方法DoFor(),控制mForm中的TextBox.Text显示;
    3.当循环完毕后,我想关闭Close()由主线程创建的mForm,这时和楼主类似的问题出现了,我希望在子线程循环方法DoFor()中的for()循环结束后加上 mForm.Close();但这里会提示mForm不是当前线程创建的对象,于是采用invoke方法,顺利解决,部分代码如下:

    C# code?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
            myForm mForm= null;//myForm是之前定义的一个窗体类
            private delegate void OnClose();//定义委托
            //省略其他代码。。。
             //主线程按钮点击事件
            private void button1_Click(object sender, EventArgs e)
            {
                //创建弹出窗体
                mForm= new myForm (true, 1, 100, ProgressBarStyle.Continuous);
                mForm.Show();
                //新线程
                Thread mThread = new Thread(new ThreadStart(DoFor));
                mThread.Start();  
            }
            private void DoFor()
            
                for (int i = 1; i <= 100; i++)
                {
                    System.Threading.Thread.Sleep(10);
                    mForm.OnSetValue(i);//这里改变弹出窗口的一个TextBox的Text属性
                }
                //循环结束后
                this.Invoke(new OnClose(DoClose));//子线程中关闭主线程创建的对象
     
            }
            //委托指向的方法
            private void DoClose()
            {
                mForm.Close();
            }
        }

    希望对你有帮助!


    出处:http://bbs.csdn.net/topics/300091034

    ==

    自己总结子线程通知主线程,代码如下:

            private void updateUI(string s)
            {
                textBox1.Text += s;
            }
    
            public delegate void SetValueHandler(string value);
    
            private void doWork()
            {
                string val = "good
    ";
                if (this.textBox1.InvokeRequired)
                {
                    // 在子线程中调用此方法时,通过Invoke转成主线程执行
                    //this.textBox1.Invoke(new SetValueHandler(updateUI), val);  //方式一:通过代理创建的方法更新界面
                    this.Invoke(new EventHandler(delegate { textBox1.Text += val; }));  //方式二:使用匿名代理来更新界面
                    return;
                }
                // 设置X值并显示
                textBox1.Text += val.ToString();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                tm.Start();
            }

    上面的代码是窗体应用程序,子线程更新主线程,使用方式一和方式二都可以实现。

    再给个WPF程序的子线程更新主线程的代码:

            private void button2_Click(object sender, RoutedEventArgs e)
            {
                System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(updateWork));
                t.Start();
            }
    
            delegate void updateUIHandler(double[] a);
    
            private void updateWork()
            {
                double[] _tt;
    
                updateUIHandler mothed = new updateUIHandler(updateUI);
                while (true)
                {
                    _tt = GetValue();  //用于获取一个数组
                    //this.Dispatcher.Invoke(mothed, _t); //方式一::通过代理创建的方法更新界面中的数据
                    base.Dispatcher.BeginInvoke(new Action(delegate { for (int i = 0; i < _tt.Length; i++) { _lindData.Append(_tt[i]); } }));//方式二:使用匿名代理来更新界面中的数据
                    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(0.5));
                }
            }
    
            private void updateUI(double[] _t)
            {
                for (int i = 0; i < _t.Length; i++)
                {
                    _lindData.Append(_t[i]);
                }
            }

    在wpf程序中需要使用this.Dispatcher.Invoke或者base.Dispatcher.BeginInvoke方法进行主线程数据的更新。

    以上程序仅供大家参考。

    在写一个方式:

    //在多线程执行的方法中,调用执行 : ShowFormAsyn(f, fName);
    
            private void ShowFormAsyn(Form f, string fName)
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(new EventHandler(delegate { ShowFormAsyn(f, fName); }));
                }
                else
                {
                    f.MdiParent = this;
                    f.Parent = subpanel3;
                    f.Show();
                }
            }
  • 相关阅读:
    做好产品经理,需要具备哪些技能?
    【FastAPI 学习 四】 日志配置
    【FastAPI 学习三】 FastAPI SqlAlchemy MySql表迁移
    【FastAPI 学习 二】SqlAlchemy Model模型类
    【FastAPI 学习一】配置文件
    Python 时间操作 格式化“2020-10-16T17:36:00+08:00“时间
    Python sqlalchemy 原生SQL LIKE 查询
    Git 使用笔记
    数据清洗(一)
    PDF文件转换为TXT文件
  • 原文地址:https://www.cnblogs.com/mq0036/p/3678510.html
Copyright © 2020-2023  润新知