zoukankan      html  css  js  c++  java
  • [C#] 多线程总结(结合进度条)

    (一)使用线程的理由

    1、可以使用线程将代码同其他代码隔离,提高应用程序的可靠性。

    2、可以使用线程来简化编码。

    3、可以使用线程来实现并发执行。

    (二)基本知识

    1、进程与线程:进程作为操作系统执行程序的基本单位,拥有应用程序的资源,进程包含线程,进程的资源被线程共享,线程不拥有资源。

    2、前台线程和后台线程:通过Thread类新建线程默认为前台线程。当所有前台线程关闭时,所有的后台线程也会被直接终止,不会抛出异常。

    3、挂起(Suspend)和唤醒(Resume):由于线程的执行顺序和程序的执行情况不可预知,所以使用挂起和唤醒容易发生死锁的情况,在实际应用中应该尽量少用。

    4、阻塞线程:Join,阻塞调用线程,直到该线程终止。

    5、终止线程:Abort:抛出 ThreadAbortException 异常让线程终止,终止后的线程不可唤醒。Interrupt:抛出 ThreadInterruptException 异常让线程终止,通过捕获异常可以继续执行。

    6、线程优先级:AboveNormal BelowNormal Highest Lowest Normal,默认为Normal。

    (三) 线程生命周期

    1. 未启动状态:当线程实例被创建但 Start 方法未被调用时的状况。
    2. 就绪状态:当线程准备好运行并等待 CPU 周期时的状况。
    3. 不可运行状态死亡状态:当线程已完成执行或已中止时的状况。
      • 已经调用 Sleep 方法
      • 已经调用 Wait 方法
      • 通过 I/O 操作阻塞

    (四) 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 + "
    ";
        _msg += "当前托管线程的唯一标识:" + t.ManagedThreadId + "
    ";
        _msg += "线程名称:" + t.Name + "
    ";
        _msg += "当前线程的状态:" + t.ThreadState;
        MessageBox.Show("消息:
    " + _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以上版本)

    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

    四  异步委托

    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

     

    六  Task+事件+控制(暂停、继续):

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace TaskTest
    {
        public partial class Form1 : Form
        {
            public event EventHandler<MyEventArgs> MyNotify;
            private delegate void DelegateSetProgress(MyEventArgs e);
            CancellationTokenSource tokenSource;
            CancellationToken token;
            ManualResetEvent reset;
    
            public Form1()
            {
                InitializeComponent();
                MyNotify += new EventHandler<MyEventArgs>(GetProgress);            
            }
    
            private void SetProgress(MyEventArgs e)
            {
                if(progressBar1.InvokeRequired)
                {
                    Invoke(new DelegateSetProgress(SetProgress), e);
                }
                else
                {
                    progressBar1.Value = e.value;
                    txtMessage.AppendText(e.text);
                }
            }
    
            private void btnStart_Click(object sender, EventArgs e)
            {
                tokenSource = new CancellationTokenSource();
                token = tokenSource.Token;
                reset = new ManualResetEvent(true); // 初始化为true时执行WaitOne不阻塞
                MyNotify(null, new MyEventArgs() { value = 0, text = $"程序已经启动
    " });
                Task.Run(() =>
                {
                    for (int i = 1; i <= 100; i++)
                    {
                        if (token.IsCancellationRequested) return;
                        reset.WaitOne();
                        MyNotify(null, new MyEventArgs() { value = i, text = $"进度为:{i}/100 
    " });
                        Thread.Sleep(100);
                    }
                },token);
            }
    
            private void GetProgress(object sender,EventArgs e)
            {
                SetProgress(e as MyEventArgs);
            }
    
            private void btnPause_Click(object sender, EventArgs e)
            {
                btnPause.Text = btnPause.Text == "暂停" ? "继续" : "暂停";
                if (btnPause.Text == "暂停")
                    reset.Set();
                else
                    reset.Reset();
            }
    
            private void btnStop_Click(object sender, EventArgs e)
            {
                tokenSource.Cancel();
            }
        }
    
        public class MyEventArgs : EventArgs
        {
            public int value = 0;
            public string text = string.Empty;
        }
    }

     

    七  参考资料:

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

    ☆多线程讲解 http://www.w3cschool.cc/csharp/csharp-multithreading.html

  • 相关阅读:
    git--简单操作
    flask--简记
    Python--进阶处理9
    Python--比较两个字典部分value是否相等
    Python--进阶处理8
    Python--进阶处理7
    Python--进阶处理6
    Python--进阶处理5
    java7连接数据库 网页 添加学生信息测试
    使用类的静态字段和构造函数,可以跟踪某个类所创建对象的个数。请写一个类,在任何时候都可以向它查询“你已经创建了多少个对象?”
  • 原文地址:https://www.cnblogs.com/zhaoshujie/p/9664915.html
Copyright © 2011-2022 走看看