1. 程式人生 > >2017.10.21 C# 多執行緒控制控制元件例項

2017.10.21 C# 多執行緒控制控制元件例項

直接上程式碼片段

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; }
        }
    }
}