我创建了一个调用webserver的线程 - 读取一些数据 - 将行写入DataTable
My Current Thread - 等待新行到达 - 将数据传递给系统
问题是我的编写器线程在尝试将行写入Datatable时进入Wait-Sleep-Join模式(从线程工具窗口了解)
代码结构是这样的:
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 :(得分:2)
问题是,如果在DataTable中添加行,DataTable将引发事件。这些事件是来自wiforms / wpf的钩子UI控件。引发事件后控件“想要做事”,但当前线程不是UI线程,而是工作线程。这是问题的核心。
解决方案是在工作线程中加载数据表单服务器,但是在UI线程中向DataTable添加行。
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);
});
}
}
修改强>
关于Winforms中多线程的好文章在CodeProject上:What's up with BeginInvoke?