2011-08-07 55 views
0

我有一個表單,並沒有control.I試圖從數據庫中獲取控件,所以我的項目是慢我認爲我可以使用線程,但我得到一個錯誤。多線程錯誤

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); 

我試着用這個代碼。但它不work.It加入相同的控制時間兩次,3次,4次

哪裏是我的錯嗎? 感謝

回答

2

您關閉了循環變量:

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

你正在創建循環變量,不其當時值的開合 - 因爲線程將只開始了很短的時間後,循環已完成,每個線程將使用當時的循環變量的值,這將是最後一行。

在循環中而不是創建一個局部變量,並在您的代理使用它:

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

另見"Closing over the loop variable considered harmful"

+0

它的工作非常感謝lot.But控制一定要來「ID」 asceding 有時它不來asceding – YardimaIhtiyaciOlan

+1

也許你應該改變SQL和包括'ORDER BY Id' ... – Yahia

+0

@YardimaIhtiyaciOlan:除了在SQL中排序時,不能控制線程實際執行的時間 - 順序不能保證,要實現這一點,您需要一種不同的方法。此外,您當前的代碼沒有多大意義 - 使用多線程的開銷並不值得您實際執行的操作。 – BrokenGlass

0

除了您已經創建了一個循環變量有一對夫婦一個封閉的事實與您的一般方法相關的主要問題。

首先,爲DataTable中的每一行創建一個線程不是一個好主意。事情是創建和啓動線程是花費和消耗大量的資源。您需要明智地選擇創建線程的方式和時間。例如,運行10,000個線程(假設DataTable中有10,000個相應的行)不會很好地工作。

但是,即使您使用ThreadPool通過QueueUserWorkItem,異步委託或通過啓動新的Task轉移到更理智的方法,但還有另一個大問題。你打算在另一個線程上發生的操作被封送回UI線程。在這種情況下使用線程絕對沒有用處。事實上,它使所有事情變得更糟,因爲線程根本沒有任何有用的工作。而且它需要通過Control.Invoke進行昂貴的編組操作才能完成任何事情。換句話說,你的UI線程告訴一個工作者線程做一些事情,工作線程轉過來說「我不想,你這樣做」。

更好的方法是執行SQL命令並在另一個線程上填充DataTable。完成後,您可以將所有這些TextBox控件添加到UI線程的表單中。實際上,使用UI元素做任何事情都必須從UI線程完成,因此您在這裏確實沒有多少可接受的選項。