使用invoke避免线程错误的正确方法是什么?

时间:2014-07-03 23:40:21

标签: c# multithreading delegates invoke

我最近一直在学习C#而且有一个问题,我似乎无法绕过头脑。请原谅我,如果这是noobish,因为我对C#很新,但我的问题是关于委托和调用。 我已经在线阅读了很多教程并观看了许多关于此的教程,但我仍然在代码中遇到同样的错误,我似乎并没有抓住细微之处。据我所知,委托是指向函数的指针,可用于从另一个线程调用该函数来更新文本框。我理解创建一个委托,我认为我做的很多但是当我从威胁中调用委托时我总是得到错误跨线程操作无效:控制'textBox1'从线程以外的线程访问它创建于。

回调似乎是有用的,因为它正在调用它所设计的函数,但它似乎没有在正确的线程上执行它,我认为这样做的全部意义。我知道可以选择将警告中断设置为false但我宁愿了解我做错了什么以及如何正确编写这种类型的方法。我感谢您提供的任何帮助,建议或答案,因为我不确定任何更多的教程是否让我更接近于了解我哪里出错了。

我的代码非常基础,因为我只是想了解正确编码多线程的最基本概念。以下是我的代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Media;
using System.Threading;
using System.Reflection;

namespace WindowsFormsApplication3
{   

    //declair delegate name(vars) CORRECT
    public delegate void Textboxdelegate(Int64 MyVar);

    public partial class Form1 : Form
    {

         public Form1()
         {
             InitializeComponent();
         }

         public void button1_Click(object sender, EventArgs e)
         {
             runme();
         }

         public void runme()
         {
             textBox1.Text = "87";
             textupdate(44);

             int target = 0;
             Textboxdelegate TD = new Textboxdelegate(textupdate);
             Number number = new Number(target, TD);
             TD(11);
             Thread thread1 = new Thread(new ThreadStart(number.worker));
             thread1.Start();

         }
        public void textupdate(Int64 cntr) 
        {
           textBox1.Text += cntr.ToString();
        }

    }

    class Number
    {

    int _target;
    Textboxdelegate _callbackMethod;

    public Number(int target, Textboxdelegate TDD)
    {
        this._target = target;
        this._callbackMethod = TDD;
    }

    public void worker()
    {

            Int64 counter = 0;
            byte[] lifeforms = new byte[2146435071];

            for (long y = 1; y <= 2146; y++)
            {

                for (long X = 1; X <= 1000000; X++)
                {
                    lifeforms[X * y] = 20;
                }

                counter += 1;
                if(_callbackMethod != null)
                {
                _callbackMethod(counter);
                }

            }

            MessageBox.Show("Done!");
        }

    }
}

1 个答案:

答案 0 :(得分:1)

这个粗略的例子应该为你想要做的事情做到:

    //public delegate void Textboxdelegate(Int64 MyVar);

    public partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
        }

        public Action<Int64> Textboxdelegate;
        public void runme()
        {
            textBox1.Text = "87";
            textupdate(44);

            int target = 0;
            Textboxdelegate = textupdate;
            Number number = new Number(target, Textboxdelegate,this);
            Textboxdelegate(11);
            Thread thread1 = new Thread(new ThreadStart(number.worker));
            thread1.Start();

        }
        public void textupdate(Int64 cntr)
        {
            textBox1.Text += cntr.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            runme();
        }

    }

    class Number
    {

        int _target;
        Action<Int64> _callbackMethod;
        Form1 frm;

        public Number(int target, Action<Int64> act,Form1 frm)
        {
            this._target = target;
            this._callbackMethod = act;
            this.frm = frm;
        }

        public void worker()
        {

            Int64 counter = 0;
            byte[] lifeforms = new byte[214643507];

            for (long y = 1; y <= 2146; y++)
            {

                for (long X = 1; X <= 100000; X++)
                {
                    lifeforms[X * y] = 20;
                }

                counter += 1;
                if (_callbackMethod != null)
                {
                    if (frm.InvokeRequired)
                    {
                        frm.Invoke(_callbackMethod,new object[]{counter});
                    }
                    else
                    {
                        _callbackMethod(counter);
                    }
                }

            }

            MessageBox.Show("Done!");
        }

    }

控件具有thread-afinity,这意味着它们只能从创建它们的线程访问,并且您可以通过另一个线程访问它们。现在Control类的Invoke方法(表单的基础及其所有控件)将允许你访问它们(非常概括的解释)。