2011-06-27 2 views
2

J'ai créé un fil qui appelle un serveur web - lit certaines données - écrit des lignes à une DataTableDiscussion Goes en attente ou de l'état de veille lorsque vous essayez d'ajouter des lignes à Datatable

Mon fil actuel qui - attend jusqu'à ce que de nouvelles lignes arrivent - transmettre les données au système

le problème est mon thread d'écriture va en attente-Sleep-Join Mode (est venu à connaître de la fenêtre d'outil de fil) quand il tente d'écrire des lignes à Datatable

la structure du code est quelque chose comme ceci:

class DataRetriever 
{ 
    Thread GetReport; 

    private DataTable ServerData; 

    int rowCount = 0; 

    private int _lastReadedRowNo = -1; 

    public GetData() 
    { 
     thrGetReport = new Thread(new ThreadStart(fn_thrGetReport)); 
       thrGetReport.Name = "CallServer"; 
       thrGetReport.IsBackground = true; 
       thrGetReport.Start(); 
    } 

    //Writer Thread Executes this 
    private void fn_thrGetReport() 
     { 
      for (int i = 0; i < cnt; i++) 
      { 
       DataRowCollection drcTemp = server.GetAnswer(parameter); 

       for (int j = 0; j < drcTemp.Count; j++) 
       {      
        ServerData.Rows.Add(drcTemp[j].ItemArray); // Here thread goes in Sleep/wait Mode 
        Interlocked.Increment(ref rowCount); 
       } 
      } 

     } 

    //This executes in Current Thread 
    public bool Read 
     { 
      get 
      {   
       if (no more data to ask condition) 
       { 
        return false; 
       } 
       else 
       { 
        //wait till new rows are not entered          
        while (rowCount <= (_lastReadRowNo + 1)) //Writer thread is in sleep/wait mode so this piece of code executes infinetly 
        ;      


        while (Condition Here) 
        { 
         // Read Datarows here 
       //Copy the Read rows to some _toReturndt 
         i++; 
        } 

        _lastReadRowNo = i - 1; 
        return true; 
       } 
      } 
     } 


     public DataRowCollection GetNextData() 
     { 
      DataTable temp = _toReturnDt; 
      _toReturnDt.Rows.Clear(); 
      return temp.Rows; 
     } 
} 


public class DataProcessor 
{ 

    public GetnProcess() 
    { 
     DataRetriever DataRetriever1 = new DataRetriever(); 
     DataRetriever1.GetData(); 

     while (this.DataRetriever1.Read) 
     { 
      DataRowCollection drc = this.DataRetriever1.GetNextData(); 
     } 
    } 
} 
+0

Est-ce DataTable binded à un certain contrôle de l'interface utilisateur ou ailleurs? – TcKs

+0

oui c'est lié à datagridview, et c'est pourquoi son erreur me donne.Merci TcKs. – Hakim

Répondre

2

Le problème est que, si vous ajoutez une ligne dans DataTable, le DataTable déclenche un événement. Pour les événements sont des contrôles d'interface utilisateur à partir de Wiforms/WFP. Les contrôles "veut faire chose" après que l'événement est déclenché, mais le thread actuel n'est pas un thread UI, mais le thread de travail. C'est le coeur du problème.

La solution consiste à charger le serveur de formulaire de données dans le thread de travail, mais à ajouter des lignes au DataTable dans le thread d'interface utilisateur.

DataRetriever.LoadDataFromServer(this.gridView1, this.myDataTable); 
// ... elsewhere ... 
public class DataRetriever { 
    // uiSynchronizer can run delegates in UI thread 
    // uiSynchronizer can be instance of "System.Windows.Forms.Control" (or derived) class 
    public void LoadDataFromServer(ISynchronizeInvoke uiSynchronizer, DataTable target) { 
     // QueueUserWorkItem runs delegate in separated thread 
     ThreadPool.QueueUserWorkItem((_state)=>{ 
      // getting rows from server 
      var serverRows = server.GetAnswer(parameter); 

      // addRows delegate must be called on UI thread 
      Action addRows =()=> { 
       try { 
        target.BeginLoadData(); 
        foreach(DataRow in serverRow in serverRows) { 
         target.Rows.Add(serverRow.ItemArray); 
        } 
       } 
       finally { 
        target.EndLoadData(); 
       } 
      }; 

      // uiSynchronizer.Invoke runs "addRows" delegate on UI thread 
      uiSynchronizer.Invoke(addRows); 
     }); 
    } 
} 

EDIT:

Le bon article sur multithreading Winforms est sur CodeProject: What's up with BeginInvoke?

Questions connexes