1. 程式人生 > >[C#] 多線程總結(結合進度條)

[C#] 多線程總結(結合進度條)

ali .repo pro 上下文 回調函數 實例 blank type 後臺

線程生命周期

  1. 未啟動狀態:當線程實例被創建但 Start 方法未被調用時的狀況。
  2. 就緒狀態:當線程準備好運行並等待 CPU 周期時的狀況。
  3. 不可運行狀態
    • 已經調用 Sleep 方法
    • 已經調用 Wait 方法
    • 通過 I/O 操作阻塞
  4. 死亡狀態:當線程已完成執行或已中止時的狀況。

Thread 常用方法:

  • public void Interrupt() 中斷處於 WaitSleepJoin 線程狀態的線程。
  • public void Join() 在繼續執行標準的 COM 和 SendMessage 消息泵處理期間,阻塞調用線程,直到某個線程終止為止。
  • public void Start() 開始一個線程
  • public static void Sleep(int millisecondsTimeout) 讓線程暫停一段時間

一 普通線程

分為兩種,一種是不需要給子線程傳參數,Thread t = new Thread(new ThreadStart(void () target)); 另一種是要給子線程傳一個參數,Thread t = new Thread(new ParameterizedThreadStart(void (object) target));

技術分享圖片
// 普通線程
private void btn1_Click(object sender, EventArgs e)
{
    progressBar.Value 
= 0; Thread tt = new Thread(new ThreadStart(DoWork1)); tt.Name = "不帶參數普通線程"; tt.Start(); Thread t = new Thread(new ParameterizedThreadStart(DoWork2)); t.Name = "帶參數普通線程"; t.IsBackground = true; t.Start(100); _msg += "當前線程的執行狀態:" + t.IsAlive + "\r\n"; _msg += "當前托管線程的唯一標識:
" + t.ManagedThreadId + "\r\n"; _msg += "線程名稱:" + t.Name + "\r\n"; _msg += "當前線程的狀態:" + t.ThreadState; MessageBox.Show("消息:\r\n" + _msg, "提示", MessageBoxButtons.OK); } // 線程方法 private void DoWork1() { for (int i = 0; i < 100; i++) { // 跨線程訪問 UI,BeginInvoke 采用異步委托 progressBar.BeginInvoke(new EventHandler((sender, e) => { progressBar.Value = i; }), null); } } // 線程方法 private void DoWork2(object obj) { for (int i = 0; i < (int)obj; i++) { progressBar.BeginInvoke(new EventHandler((sender, e) => { progressBar.Value = i; }), null); } }
普通線程

二 線程池

public static bool QueueUserWorkItem(WaitCallback);

public static bool QueueUserWorkItem(WaitCallback, object);

線程池默認為後臺線程(IsBackground)

技術分享圖片
private void btn3_Click(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(DoWork2, 100);
    // 或者
    ThreadPool.QueueUserWorkItem((s) =>
    {
        int minWorkerThreads, minCompletionPortThreads, maxWorkerThreads, maxCompletionPortThreads;
        ThreadPool.GetMinThreads(out minWorkerThreads, out minCompletionPortThreads);
        ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxCompletionPortThreads);
        MessageBox.Show(String.Format("WorkerThreads = {0} ~ {1}, CompletionPortThreads = {2} ~ {3}",
            minWorkerThreads, maxWorkerThreads, minCompletionPortThreads, maxCompletionPortThreads));
        DoWork2(100);
    });
}
// 線程方法
private void DoWork2(object obj)
{
    for (int i = 0; i < (int)obj; i++)
    {
        // Thread.Sleep(50);
        progressBar.BeginInvoke(new EventHandler((sender, e) =>
        {
            progressBar.Value = i;
        }), null);
    }
}
線程池

三 BackgroundWorker

技術分享圖片
private void btn4_Click(object sender, EventArgs e)
{
    progressBar.Value = 0;
    BackgroundWorker bw = new BackgroundWorker();
    bw.WorkerReportsProgress = true;// 是否報告進度更新
    // 線程執行
    bw.DoWork += new DoWorkEventHandler((obj, args) =>
    {
        for (int i = 0; i < 100; i++)
        {
            bw.ReportProgress(i);
        }
    });
    // UI主線程顯示進度
    bw.ProgressChanged += (obj, progressChangedEventArgs) =>
    {
        progressBar.Value = progressChangedEventArgs.ProgressPercentage;
    };
    // 線程執行完成後的回調函數
    bw.RunWorkerCompleted += (obj, runWorkerCompletedEventArgs) =>
    {
        MessageBox.Show("子線程執行完成!");
    };
    if (!bw.IsBusy)
    {
        bw.RunWorkerAsync();
    }
}
BackgroundWorker

三 Task(.NET 4.0以上版本)

參考博客 http://www.cnblogs.com/luxiaoxun/p/3280146.html

技術分享圖片
private void btn5_Click(object sender, EventArgs e)
{
    progressBar.Value = 0;
    Task<bool> t = new Task<bool>(maxValue => DoWork((int)maxValue), progressBar.Maximum);
    t.Start();
    t.Wait();
    // 任務完成後繼續延續任務
    Task cwt = t.ContinueWith(task => MessageBox.Show("The result is " + t.Result));
}
// 線程方法
private bool DoWork(int maxValue)
{
    for (int n = 0; n < maxValue; n++)
    {
        progressBar.BeginInvoke(new EventHandler((sender, e) =>
        {
            progressBar.Value = n;
        }), null);
    }

    return true;
}
Task

四 異步委托

參考博客 http://www.cnblogs.com/luxiaoxun/p/3280146.html

技術分享圖片
public delegate string MyDelegate(object arg);

private void btn6_Click(object sender, EventArgs e)
{
    MyDelegate myDelegate = new MyDelegate(DoWork3);
    IAsyncResult result = myDelegate.BeginInvoke(100, DoWork2Callback, "回調函數參數");

    // 異步執行完成
    string resultStr = myDelegate.EndInvoke(result);
}

// 線程函數
private string DoWork3(object arg)
{
    for (int n = 0; n < (int)arg; n++)
    {
        progressBar.BeginInvoke(new EventHandler((sender, e) =>
        {
            progressBar.Value = n;
        }), null);
    }

    return "Finished";
}

// 異步回調函數
private void DoWork2Callback(IAsyncResult arg)
{
    MessageBox.Show(arg.AsyncState.ToString());
}
異步委托

五 附 跨線程訪問UI之 SynchronizationContext (同步上下文)

技術分享圖片
private void btn2_Click(object sender, EventArgs e)
{
    SynchronizationContext context = SynchronizationContext.Current;
    new Thread(() =>
    {
        for (int i = 0; i < 100; i++)
        {
            // Send方法是發送一個異步請求消息
            //context.Send((s) =>
            //{
            //    progressBar.Value = i;
            //}, null);
            // Post方法是發送一個同步請求消息
            context.Post((s) =>
            {
                progressBar.Value = i;
            }, null);
        }
    }).Start();
}
SynchronizationContext

六 參考資料:

☆多線程講解 http://www.w3cschool.cc/csharp/csharp-multithreading.html

☆http://www.cnblogs.com/luxiaoxun/p/3280146.html

[C#] 多線程總結(結合進度條)