关于Invoke和BeginInvoke的一些认识
前段时间做CS项目时,由于需要在工作线程中更新界面,所以就使用了Control.BeginInvoke方法,运行结果却总是和预期的不一样。经过调试发现,在工作线程中有两个更新界面的地方,一个是给界面中的table清空,一个是填充table,由于这两个动作是交叉运行的,时常会出现填充的操作还没有结束,突然就跳到清空table的代码段中。
代码A:
private void bt_AutoDown_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(this.autoDownload));
t.Start();
}
{
Thread t = new Thread(new ThreadStart(this.autoDownload));
t.Start();
}
代码B
private void autoDownload()
{
foreach (string str in fileList)
{
...............//省略
this.Invoke(new insertTableInfoHandler(insertTableInfo), "a", "a");
..............//省略
foreach (string gfsFile in gfsList)
{
if (!string.IsNullOrEmpty(gfsFile) && fileNameMatch(gfsFile))
{
this.Invoke(new insertTableInfoHandler(insertTableInfo),str,gfsFile);
}
}
..............//省略
}
}
{
foreach (string str in fileList)
{
...............//省略
this.Invoke(new insertTableInfoHandler(insertTableInfo), "a", "a");
..............//省略
foreach (string gfsFile in gfsList)
{
if (!string.IsNullOrEmpty(gfsFile) && fileNameMatch(gfsFile))
{
this.Invoke(new insertTableInfoHandler(insertTableInfo),str,gfsFile);
}
}
..............//省略
}
}
代码C:
/// <summary>
/// 填充Table1,若dataTime于filename相同则清空table1
/// </summary>
/// <param name="dateTime"></param>
/// <param name="fileName"></param>
private void insertTableInfo(string dateTime, string fileName)
{
lock (LockObj)
{
if (string.Equals(dateTime, fileName))
{
///清空table
}
else
{
///填充table
}
/// 填充Table1,若dataTime于filename相同则清空table1
/// </summary>
/// <param name="dateTime"></param>
/// <param name="fileName"></param>
private void insertTableInfo(string dateTime, string fileName)
{
lock (LockObj)
{
if (string.Equals(dateTime, fileName))
{
///清空table
}
else
{
///填充table
}
}
}
后来将操作table的这段代码作为临界区lock起来,然后将Control.BeginInvoke方法改为Control.Invoke方法,就不会出现上面提到的问题了
由此得出一个重要结论:
Invoke 与BeginInvoke两者的区别就是一个导致工作线程等待,而另外一个则不会。