C#多线程、跨线程与线程安全的示例详解(三种不同方法)
代码如下 |
复制代码 |
using System.Threading;
public static class Extensions
{
//控件扩展方法(用于跨线程操作),因为为了线程的安全,防止资源竞争出现死锁或不一致的状态,.NET是不允许进行跨线程访问窗体控件的。
public static void SafeCall(this Control ctrl, Action callback)
{
if (ctrl.InvokeRequired)
{
ctrl.Invoke(callback);
}
else
{
callback();
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;//方法二(禁用异常,不检查跨线程调用的安全问题,可以自由拖动窗体,不过在严格条件下也不可取,数据可能不一致)
//方法三(推荐使用)
//把你要保护起来的代码作为一个回调,然后任何需要保护一些代码的地方都可以这样调用
ThreadPool.QueueUserWorkItem(h =>
{
int i = 0;
while (true)
{
//如果没有SafeCall方法,将出现“线程间操作无效: 从不是创建控件“textBox1”的线程访问它。”的错误
////匿名委托
//textBox1.SafeCall(delegate()
//{
// textBox1.Text = (i++).ToString();
//});
//Lambda表达式
textBox1.SafeCall(() =>
{
textBox1.Text = (i++).ToString();
});
//Thread.Sleep(100);
}
});
}
//抽奖示例
public bool flag = true;
public void choujiang()
{
flag = true;
while (flag)
{
Random rnd = new Random();
textBox1.Text = rnd.Next(1, 100).ToString();
//Application.DoEvents();//方法一:这样也可以防止UI界面线程的阻塞,不至于被卡死。但是在拖动界面或其他操作的时候,程序会被暂停
}
}
//开始
private void button1_Click(object sender, EventArgs e)
{
//choujiang();//方法一
new Action(choujiang).BeginInvoke(null, null);//方法二
}
//暂停
private void button2_Click(object sender, EventArgs e)
{
flag = false;
}
}
|
异步线程池
代码如下 |
复制代码 |
delegate double weituo(double d);
static weituo w = new weituo(perimeter);
///
/// 计算周长
///
///
public static double perimeter(double d)
{
return d * Math.PI;
}
///
/// 异步完成后回调的方法
///
///
public static void method(IAsyncResult result)
{
Console.Write("hi~");
Console.WriteLine(w.EndInvoke(result));
}
static void Main(string[] args)
{
//开始异步执行
w.BeginInvoke(10, new AsyncCallback(method), null);
w.BeginInvoke(20, new AsyncCallback(method), null);
Console.Read();
}
_________________________________
///
/// 静态方法不需要实例化
///
///
public static void perimeter(object d)
{
Console.WriteLine(Math.PI * (double)d);
Thread.Sleep(1000);
}
static void Main(string[] args)
{
int i = 1;
WaitCallback wcb = new WaitCallback(perimeter);
while (i < 15)
{
//将任务排入队列以便执行,您的回调方法将在某个线程池线程可用时执行
ThreadPool.QueueUserWorkItem(wcb, (double)i);
++i;
}
Console.Read();
}
|
总结
优点:
·使用线程可以把占据长时间的程序中的任务放到后台去处理
·用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
·程序的运行速度可能加快
·在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
缺点:
·如果有大量的线程,会影响性能,因为操作系统需要在他们之间切换;
·更多的线程需要更多的内存空间
·线程会给程序带来更多的bug,因此要小心使用
·线程的中止需要考虑其对程序运行的影响
·通常块模型数据是在多个线程间共享的,需要一个合适的锁系统替换掉数据共享