简体   繁体   English

多线程错误

[英]Multithreading error

I have a form and there is no control.I am trying get the controls from Database so my project is slow i thinks i can use threading but I get a error. 我有一个表单,没有控制。我正在尝试从数据库获取控件,所以我的项目很慢,我认为我可以使用线程,但我得到一个错误。

    void Form_Load(object sender,EventArgs e)
    {

    SqlDataAdapter adap=new SqlDataAdapter("Select * from MyControls");
    DataTable dt=new DataTable();

    adap.Fiil(dt);

     foreach(DataRow dr in dt.Rows) 
     {
      ThreadStart ts=delegate{ Sample1(dr) };
Thread th=new Thread(ts);
th.start();

     }

    }

    public void Sample1(DataRow dr)
    {
    this.Invoke(new AddControlsDelegate(AddControls),new object[] {dr } );
    }
    public void AddControls(DataRow dr)
    {
    TextBox tx=new TextBox();
    tx.Name=dr["Id"].ToString();
    this.Controls.Add(tx);

    }

public delegate void AddControlsDelegate(DataRow dr);

I am tryin with this code .But it dont work.It adding same control twice time,3 time,4 time 我试着用这个代码。但它不工作。它添加相同的控制两次,3次,4次

Where is the my wrong? 我哪里错了? thanks 谢谢

You are closing over the loop variable: 您正在关闭循环变量:

 foreach(DataRow dr in dt.Rows) 
 {
   ThreadStart ts=delegate{ Sample1(dr) };
   ...
 }

You are creating a closure of the loop variable , not its value at the time - since the thread will be only started a little time later, the loop has completed and each thread will use the value of the loop variable at that time , which will be the last row. 您正在创建循环变量的封闭,而不是它的时间价值 -因为线程会才开始一点点的时间过去了,循环已经完成,每个线程将使用循环变量的值, 在那个时候 ,这将是最后一排。

Instead create a local variable within the loop and use it in your delegate: 而是在循环中创建一个局部变量并在您的委托中使用它:

 foreach(DataRow dr in dt.Rows) 
 {
    DataRow currentRow = dr;
    ThreadStart ts=delegate{ Sample1(currentRow) };
    Thread th=new Thread(ts);
    th.start();
 }

Also see "Closing over the loop variable considered harmful" 另请参阅“关闭循环变量被认为有害”

Aside from the fact that you have created a closure over a loop variable there a couple of pretty major problems with your general approach. 除了你已经在循环变量上创建了一个闭包这一事实之外,你的一般方法还存在一些相当大的问题。

First, creating one thread for each row in the DataTable is not a good idea. 首先,为DataTable每一行创建一个线程不是一个好主意。 The thing is creating and starting threads is expense and consumes a lot of resources. 事情是创建和启动线程是费用并消耗大量资源。 You need to choose wisely how and when you create threads. 您需要明智地选择创建线程的方式和时间。 For example, having 10,000 threads running (assuming there are 10,000 corresponding rows in the DataTable ) is not going to work out very well. 例如,运行10,000个线程(假设DataTable有10,000个相应的行)并不会很好。

But, even if you moved to a more sane approach using the ThreadPool via QueueUserWorkItem , asynchronous delegates, or by starting a new Task there is yet another big problem. 但是,即使您通过QueueUserWorkItem ,异步委托或通过启动新Task使用ThreadPool转向更合理的方法,还有另一个大问题。 The operation you intended to have happen on another thread winds up being marshaled back onto the UI thread. 您希望在另一个线程上发生的操作最终被封送回UI线程。 The use of threads in this case serves absolutely no purpose. 在这种情况下使用线程绝对没有用处。 In fact, it makes everything worse since the thread does no useful work at all. 事实上,它使一切变得更糟,因为线程根本没有任何有用的工作。 And it requires an expensive marshaling operation via Control.Invoke to get nothing done. 它需要通过Control.Invoke进行昂贵的编组操作才能完成任务。 In other words, your UI thread tells a worker thread to do something and the worker thread turns around and says "I don't want to, you do it instead." 换句话说,你的UI线程告诉工作线程做某事,工作线程转过来说“我不想,你这样做”。

A better approach would be to execute the SQL command and populate the DataTable on another thread. 更好的方法是执行SQL命令并在另一个线程上填充DataTable Once that is complete you can then add all of those TextBox controls to the form from the UI thread. 完成后,您可以从UI线程将所有这些TextBox控件添加到表单中。 Actually, doing anything with a UI element must done from the UI thread so you really do not have many acceptable options here. 实际上,使用UI元素执行任何操作都必须从UI线程完成,因此您实际上没有很多可接受的选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM