2017.10.20 C#跨线程操作控件的线程安全方法
来源:互联网 发布:药房进销存软件 编辑:程序博客网 时间:2024/06/05 05:09
C#跨线程操作控件的线程安全方法
在C#中,经常用到这样一个场景,Windows Form程序启动一个工作者线程执行一部分工作,这样做是为了避免速度慢的工作如果直接调用会使得主Form停止响应一段时间。
既然启动了线程,就避免不了线程之间数据传递的事情,相信你有很多种办法能解决,总之注意同步和互斥操作就好。我想说的是,工作线程处理中可能想操作某个主线程的Windows Form的Control,比如按钮,ListView等等更新工作状态之类,直接控制是不行的,不能够跨线程操作另一个线程创建的Windows Form控件。要使用委托去调用。
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Threading;namespace JPGCompact{ public partial class MainForm : Form { // 定义委托 private delegate void DelegateWriteResult(string file, bool result); // 与定义的委托签名相同的函数,操作主线程控件 private void WriteResult(string fileName, bool result) { if (result) { ListViewItem thisListItem = new ListViewItem(); thisListItem.ForeColor = Color.White; thisListItem.BackColor = Color.DarkGreen; thisListItem.SubItems[0].Text = fileName; thisListItem.SubItems.Add("成功"); lvResultList.Items.Add(thisListItem); } else { ListViewItem thisListItem = new ListViewItem(); thisListItem.ForeColor = Color.White; thisListItem.BackColor = Color.Red; thisListItem.SubItems[0].Text = fileName; thisListItem.SubItems.Add("失败"); lvResultList.Items.Add(thisListItem); } } // 启动线程 private void btnStart_Click(object sender, EventArgs e) { Thread workThread = new Thread(new ThreadStart(CompressAll)); // 设置为背景线程,主线程一旦推出,该线程也不等待而立即结束 workThread.IsBackground = true; workThread.Start(); } // 线程执行函数 private void CompressAll() { // 判断是否需要Invoke,多线程时需要 if (this.InvokeRequired) { // 通过委托调用写主线程控件的程序,传递参数放在object数组中 this.Invoke(new DelegateWriteResult(WriteResult), new object[] { item, true }); } else { // 如果不需要委托调用,则直接调用 this.WriteResult(item, true); } } }}
C# 多线程控制控件实例
该实例功能为“多线程控制UI控件”,线程函数实现自动加1。界面如下:
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Threading;namespace treadTest{ //定义委托 public delegate void ListBoxDelegate(); public partial class Form1 : Form { public Form1() { InitializeComponent(); } //委托处理方法(关联与ListBoxDelegate) private void ListBox() { if (!listBox1.InvokeRequired)//如果在UI主线程操作ListBox, { listBox1.Items.Add(++CommonData.num);//则直接进行控件操作,“与UI主线程相关联” listBox1.SelectedItem = listBox1.Items[listBox1.Items.Count - 1]; } else//如果是在另一线程操作ListBox,则启用委托 listBox1.Invoke(new ListBoxDelegate(listShow)); } //定义对UI主线程控件的操作,“与AddAuto相关联”。 private void listShow() { listBox1.Items.Add(CommonData.num); listBox1.SelectedItem = listBox1.Items[listBox1.Items.Count - 1]; } //定义线程函数 private void AddAuto() { while (CommonData.Flag == 0) { CommonData.num++; Thread.Sleep(1000); ListBox();//不能直接控制UI上的控件,所以用该方法选择使用委托 } } //在click事件中启动多线程 private void btnStart_Click(object sender, EventArgs e) { //线程标志置0,表示开启线程 CommonData.Flag = 0; //定义 ThreadStart的委托类型的参数,并使该委托指向线程函数 ListBoxDelegate mycn = new ListBoxDelegate(AddAuto); //实例化线程 Thread insertTxt = new Thread(new ThreadStart(mycn)); //启动线程 insertTxt.Start(); } private void btnAbort_Click(object sender, EventArgs e) { CommonData.Flag = 1; } private void btnCtrlMain_Click(object sender, EventArgs e) { ListBox(); } private void btnReset_Click(object sender, EventArgs e) { CommonData.num = 0; } private void btnClear_Click(object sender, EventArgs e) { listBox1.Items.Clear(); } private void btnQuit_Click(object sender, EventArgs e) { Application.Exit(); } } //全局变量解决方案 public class CommonData { private static int _Flag = 0; private static int _num = 0; public static int Flag { get { return _Flag; } set { _Flag = value; } } public static int num { get { return _num; } set { _num = value; } } }}
总结:
要使用多线程控制UI控件,必须用委托实现。调用控件的Invoke方法(Invoke方法的参数是一个委托类型的参数)。
实现步骤:
1.声明委托。
2.声明委托处理函数(判断是主线程控制UI控件,还是Invoke(多线程)控制UI控件)。
3.声明一个线程实例,将线程函数的委托传入ThreadStart()。
4.开启该线程。
5.定义该线程函数,欲控制UI控件,则调用第2步的委托处理函数,他将自己判断选择用Invoke。
6.定义Invoke需要调用的函数(如本例的listShow函数)
//***********************************************************************************************************************
在上例中,只是完成了多线程控制主线程控件的功能,如果能手动和自动同时访问全局变量时,就有可能出现线程不同步的问题。以下主要利用lock线程锁来修改解决方案,使线程同步,注意代码带动的地方。
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Threading;namespace treadTest{ //定义委托 public delegate void ListBoxDelegate(); public partial class Form1 : Form { public Form1() { InitializeComponent(); } //委托处理方法(关联与ListBoxDelegate) private void ListBox() { if (!listBox1.InvokeRequired)//如果在UI主线程操作ListBox, { listBox1.Items.Add(CommonData.plus());//则直接进行控件操作,“与UI主线程相关联” listBox1.SelectedItem = listBox1.Items[listBox1.Items.Count - 1]; } else//如果是在另一线程操作ListBox,则启用委托 listBox1.Invoke(new ListBoxDelegate(listShow)); } //定义对UI主线程控件的操作,“与AddAuto相关联”。 private void listShow() { listBox1.Items.Add(CommonData.plus()); listBox1.SelectedItem = listBox1.Items[listBox1.Items.Count - 1]; } //定义线程函数 private void AddAuto() { while (CommonData.Flag == 0) { Thread.Sleep(1000); ListBox();//不能直接控制UI上的控件,所以用该方法选择使用委托 } } //在click事件中启动多线程 private void btnStart_Click(object sender, EventArgs e) { //线程标志置0,表示开启线程 CommonData.Flag = 0; //定义 ThreadStart的委托类型的参数,并使该委托指向线程函数 ListBoxDelegate mycn = new ListBoxDelegate(AddAuto); //实例化线程 Thread insertTxt = new Thread(new ThreadStart(mycn)); //启动线程 insertTxt.Start(); } private void btnAbort_Click(object sender, EventArgs e) { CommonData.Flag = 1; } private void btnCtrlMain_Click(object sender, EventArgs e) { ListBox(); } private void btnReset_Click(object sender, EventArgs e) { CommonData.num = 0; } private void btnClear_Click(object sender, EventArgs e) { listBox1.Items.Clear(); } private void btnQuit_Click(object sender, EventArgs e) { Application.Exit(); } } //全局变量解决方案 public class CommonData { private static int _Flag = 0; private static int _num = 0; public static int plus() { lock (new object()) { return _num++; } } public static int Flag { get { return _Flag; } set { _Flag = value; } } public static int num { get { return _num; } set { _num = value; } } }}
- C#跨线程操作控件的线程安全方法
- C#跨线程操作控件的线程安全方法
- 2017.10.20 C#跨线程操作控件的线程安全方法
- C# 如何线程安全的操作控件
- C# 跨线程操作控件的线程安全性方法
- C# 跨线程操作控件
- C#跨线程操作控件
- c# 线程操作控件
- c# 线程操作控件
- C#一个线程操作另一个线程的控件的方法(转)
- C#的线程中如何操作控件?
- C#子线程的控件操作
- C#在一个线程中操作另一个线程的控件
- C#中跨线程操作控件
- C#中跨线程操作控件
- C#笔记 跨线程操作控件
- C#中工作线程和多线程跨线程操作控件
- C#线程间操作无效(跨线程访问控件)
- 【Docker】Docker运行单机版Spark
- JS替换字符串中的部分字符
- 矩阵求导
- Java文件读写操作(FileInputStream、FileReader、BufferedReader)
- 解决mysql 安装过程中start service失败的问题
- 2017.10.20 C#跨线程操作控件的线程安全方法
- 学习下Git
- [noip2016]蚯蚓 题解
- Android 禁止弹出键盘的方法
- inner总结
- 洛谷P1529 回家 Bessie Come Home
- bzoj4401块的计数 dfs
- 数据分析(一)
- 个人总结10