[C#參考]主線程和子線程之間的參數傳遞


幾個進程在大多數情況下要包含很多的子線程,那么他們之間免不了的要互相傳遞很多的參數,那么參數怎么傳遞的呢?


主線程向子線程傳遞參數的方法


第一種方法:Thraed類有一個帶參數的委托類型的重載形式,這個委托的定義如下:

public delegate void ParameterizedThreadStart(Object obj)

這個Thread類的構造方法的定義如下:

public Thread(ParameterizedThreadStart start);

下面的代碼使用了這個帶參數的委托向線程傳遞一個字符串參數:

public static void myStaticParamThreadMethod(Object obj)
{
    Console.WriteLine(obj);
}
 
static void Main(string[] args)
{
    Thread thread = new Thread(myStaticParamThreadMethod);
    thread.Start("通過委托的參數傳值");
}

注意這種形式,委托就是Thread要執行的方法,這個委托有一個類的實例對象作為參數。然后在Thread的Start()方法中把這個對象傳進去。

如果使用了不帶參數的委托,當然也能很正常的啟動線程,別學傻了。

第二種方法:定義一個類來傳遞參數

class Program
    {
        static void Main(string[] args)
        {
            MyData myData = new MyData("abcd", 1234);
            Thread thread = new Thread(myData.ThreadMethod);
            thread.Start();

            Console.ReadKey();
        }
    }//class

    //定義一個類傳遞參數
    public class MyData
    {
        private string d1;
        private int d2;

        public MyData(string d1, int d2)
        {
            this.d1 = d1;
            this.d2 = d2;
        }

        public void ThreadMethod()
        {
            Console.WriteLine(d1);
            Console.WriteLine(d2);
        }
    }//class

這種方法的特點是:子線程的執行入口是在另一個類中,這樣正好可以借助這個類的成員函數,給子線程傳參。

第三種方法:定義一個新的線程類,讓所有的子線程類都繼承自這個類

abstract class MyThread
{
    Thread thread = null;
 
    abstract public void run();
 
    public void Start()
    {
        if (thread == null)
        {
            thread = new Thread(run);
            thread.Start();
        }
    }
}
class Utility : MyThread
{
    private string d1;
    private int d2;
 
    public override void run()
    {
        Console.WriteLine(d1);
        Console.WriteLine(d2);
    }
 
}//class

其實上面的兩種方法的原理是一樣的,這是一個面向數據,一個面向線程。


子線程向主線程傳遞參數


這里看到是傳遞參數,也就是說子線程要調用主線程的一個方法,然后把參數傳遞給主線程的那個方法。說一下方法是前面已經講過的Invoke和BeginInvoke,但是那時調用主線程的方法並沒有傳遞參數,今天看一下帶參數的調用主線程的指定方法。

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 WindowsFormsApplication3
{
    public partial class Form1 : Form
    {
        private int count = 0;

        private delegate void DoWorkUIThreadDelegate();
        public Form1()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            Thread thread = new Thread(ThreadMethod);
            thread.IsBackground = true;
            thread.Start();
        }

        private void ThreadMethod()
        {
            while (true)
            {
                //lblResult.Text = DateTime.Now.ToString();
                //這句話不能直接調用,因為子線程不能直接調用UI線程中的控件
                if (this.InvokeRequired)
                {
                    this.BeginInvoke(new DoWorkUIThreadDelegate(DoWorkUIThread), null);
                }
                else
                {
                    DoWorkUIThread();
                }

                //子線程還是可以訪問UI線程的普通變量的,只是不能訪問控件
                //因為普通變量是屬於整個類的,屬於整個進程的,各個線程時共享的
                //對訪問共享的數據,加一個lock的鎖更加的好
                count++;
                Thread.Sleep(1000);
            }
            
        }

        private void DoWorkUIThread()
        {
            txtTime.Text = DateTime.Now.ToString() + " " + count;
        }
    }
}

上面的這種情況似乎用不着子線程給UI線程返回數據,反正子線程可以訪問主線程的成員變量。但是另一種情況來了,當子線程不再UI線程所在的類的時候,也就是說子線程在一個工具類中,UI類new出來一個工具類完成一定的工作,UI類可以初始化工具類,但是工具類完成了一定任務后怎么通知UI類呢?現在有這種假設:

UI類要Socket連接網絡,現在有一個SocketUtil工具可以完成這項任務,所以UI類就New出來一個SocketUtil,然后調用指定的函數,把IP和Port傳遞進去。在完成了一些任務以后,SocketUtil要反饋一些信息給UI類。讓UI類顯示反饋的信息。現在面臨兩個問題:

1. UI類怎么知道SocketUtil完成了這項任務,然后取顯示數據呢?

2. UI類即使知道了什么時候顯示信息,那么要顯示的內容,UI類怎么知道是什么呢?

第一個問題的解決方法就是事件,利用事件就能在SocketUtil完成一些任務之后,通知UI類接下來怎么做。

第二個問題就是利用Invoke讓子線程給主線程調用主線程的函數完成任務的時候,給一些參數。

這里就直接在同一個類中展示一下:

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 WindowsFormsApplication3
{
    public partial class Form1 : Form
    {
        private int count = 0;

        private delegate void DoWorkUIThreadDelegate(string name, int id);
        public Form1()
        {
            InitializeComponent();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            Thread thread = new Thread(ThreadMethod);
            thread.IsBackground = true;
            thread.Start();
        }

        private void ThreadMethod()
        {
            string strName = "stemon";
            int ID = 1;

            while (true)
            {
                //lblResult.Text = DateTime.Now.ToString();
                //這句話不能直接調用,因為子線程不能直接調用UI線程中的控件
                if (this.InvokeRequired)
                {
                    object[] myArray = new object[2];
                    //類型的裝箱是自動的
                    //類型的拆箱要強制轉換
                    myArray[0] = strName;
                    myArray[1] = ID;

                    this.BeginInvoke(new DoWorkUIThreadDelegate(DoWorkUIThread), myArray);
                }
                else
                {
                    //DoWorkUIThread(strName, ID);
                }

                //子線程還是可以訪問UI線程的普通變量的,只是不能訪問控件
                //因為普通變量是屬於整個類的,屬於整個進程的,各個線程時共享的
                //對訪問共享的數據,加一個lock的鎖更加的好
                count++;
                Thread.Sleep(1000);
            }
            
        }

        private void DoWorkUIThread(string name, int id)
        {
            txtTime.Text = name + " " + id + " " + DateTime.Now.ToString() + " " + count;
        }
    }
}

這個方法是這樣操作的,BeginInvoke可以傳遞一個數組,這個數組是boject類型的,這樣就可以把所有的參數都裝箱成object類型的,弄成一個object類型的數組,然后到調用方在拆封就可以了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM