问题:线程间操作无效

为什么会发生“线程间操作无效”的异常。

在开发winform应用程序时,如果不是控件的创建者线程试图调用该控件时,则调试器会引发一个 InvalidOperationException,并提示消息:“从不是创建控件 ***(控件名) 的线程访问它。”

在多线程调用的情况下,由于本身程序就有一个主线程,现在你又新加一个线程,资源访问的不一致性,新加的线程是不可以直接访问另一个线程里的数据,包括控件;

原因总结:控件的调用者线程不是控件的创建者线程,这是.net实现资源安全访问机制的必然结果。访问 Windows 窗体控件本质上不是线程安全的。如果多个线程同时操作某一控件的状态,则可能会迫使该控件进入一种不一致的状态。但是我们不能为了实现资源安全访问机制而坏了我们的大事。

例子:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace GrabberImage
{
public partial class Grabberimage : Form
{
#region
private GrabberDigikey.IDAL.IProduct DB_Product = new GrabberDigikey.MySQLDAL.Product();
private delegate void SetTextCallback(string text);
int cnt = 0;
#endregion
public Grabberimage()
{
InitializeComponent();
this.Lable_Count.Text = "...";
//GetCountInfo();//自己创建线程,然后控件Invoke调用委托
this.backgroundWorker1.RunWorkerAsync();//自动backgroundWorker线程,须在form设计中拖入backgroundWorker控件
}



private void BrowseFolder_Click(object sender, EventArgs e)
{
if (FolderBrowserDialog.ShowDialog(this) == DialogResult.OK)
{
SaveToLocation.Text = FolderBrowserDialog.SelectedPath;
}
}

private void button1_Click(object sender, EventArgs e)
{

}

private void GetCountInfo()
{
Thread t = new Thread(new ThreadStart(SetCountInfo));
t.Start();
}
private void SetCountInfo()
{
try
{
int cnt = DB_Product.GetCountByImage();
this.SetText("共有" + cnt * 2 + "张图片");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void SetText(string text)
{
//获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,
//因为调用方位于创建控件所在的线程以外的线程中。
if (this.Lable_Count.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
//拥有此控件的基础窗口句柄的线程上执行指定的委托
this.Invoke(d, new object[] { text });
}
else
{
this.Lable_Count.Text = text;
}
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
       //后台线程工作者要做的事
try
{
this.cnt = DB_Product.GetCountByImage();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Lable_Count.Text = "共有" + this.cnt * 2 + "张图片";
}
}
}



posted @ 2012-03-12 18:14  rock.dean  阅读(542)  评论(0编辑  收藏  举报