C#多线程

一、引言

1.1 线程概念

如果对什么是线程、什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内。

一些基本概念:
* 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
* 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
* 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。
* 线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果。
* 同步:通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。

1.1.1 并发

多线程与多进程是并发的两种途径。

1.1.1.1 多进程:

多个进程独立地运行,它们之间通过进程间常规的通信渠道传递讯息(信号,套接字,文件,管道等),这种进程间通信不是设置复杂就是速度慢,这是因为为了避免一个进程去修改另一个进程,操作系统在进程间提供了一定的保护措施,当然,这也使得编写安全的并发代码更容易。
运行多个进程也需要固定的开销:进程的启动时间,进程管理的资源消耗。

1.1.1.2 多线程

在单个进程中运行多个线程也可以并发。线程就像轻量级的进程,每个线程相互独立运行,但它们共享地址空间,所有线程访问到的大部分数据如指针、对象引用或其他数据可以在线程之间进行传递,它们都可以访问全局变量。进程之间通常共享内存,但这种共享通常难以建立且难以管理,缺少线程间数据的保护。因此,在多线程编程中,我们必须确保每个线程锁访问到的数据是一致的。

1.2 线程状态

https://www.cnblogs.com/wxd0108/p/5479442.html

本文主要示例代码:
https://github.com/landbroken/BasicKnowledge/tree/master/ThreadCSharp

二、多线程

未完待续

三、线程池

3.1 概念

百度百科:线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。

3.2 主要方法

线程池主要方法:

// 参数:
        // workerThreads:
        // 要由线程池根据需要创建的新的最小工作程序线程数。
        // completionPortThreads:
        // 要由线程池根据需要创建的新的最小空闲异步 I/O 线程数。
        // 返回结果:如果更改成功,则为 true;否则为 false。
        [SecuritySafeCritical]
        public static bool SetMinThreads(int workerThreads, int completionPortThreads);
        // 参数:
        // workerThreads:
        // 线程池中辅助线程的最大数目。
         // completionPortThreads:
        // 线程池中异步 I/O 线程的最大数目。
        // 返回结果:如果更改成功,则为 true;否则为 false。
        [SecuritySafeCritical]
        public static bool SetMaxThreads(int workerThreads, int completionPortThreads);

3.3 示例

以下是示例,用了信号灯AutoResetEvent 来判断线程池内是否运行终止:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ThreadCSharp
{
    public partial class Form1 : Form
    {
        const int cycleNum = 10;
        static AutoResetEvent myEvent = new AutoResetEvent(false);

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        public void testFun(object obj)
        {
            string output = $"{"Begin:" + DateTime.Now.ToString()}:第{obj.ToString()}个线程";
            SetMessage(textBox1, output);
            Thread.Sleep(3000);
            string end = $"{"End:" + DateTime.Now.ToString()}:第{obj.ToString()}个线程";
            SetMessage(textBox1, end);
            if (obj.ToString() == "10")
            {
                myEvent.Set();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SetMessage(textBox1, $"主线程执行!{DateTime.Now.ToString()}");
            ThreadPool.SetMinThreads(1, 1);
            ThreadPool.SetMaxThreads(5, 5);
            for (int i = 1; i <= cycleNum; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(testFun), i.ToString());
            }
            SetMessage(textBox1, $"主线程结束!{DateTime.Now.ToString()}");
            myEvent.WaitOne();//阻止当前线程,直到收到信号
            SetMessage(textBox1, $"线程池终止!{DateTime.Now.ToString()}");
        }

        delegate void SetMessageCallBack(TextBox txtIn, string MyMessage);
        private void SetMessage(TextBox txtIn, string MyMessageIn)
        {
            try
            {
                if (!MyMessageIn.EndsWith(Environment.NewLine))
                {
                    MyMessageIn += Environment.NewLine;//加上换行符
                }
                if (this.InvokeRequired)
                {
                    SetMessageCallBack tmpMessage = new SetMessageCallBack(SetMessage);
                    this.BeginInvoke(tmpMessage, new object[] { txtIn, MyMessageIn });
                }
                else
                {
                    txtIn.Text += MyMessageIn;
                }
            }
            catch (Exception ex)
            {
                //线程时间太短,容易在关闭窗口时引起异常:
                //无法访问已释放的对象。对象名:“Form1”。
                string tmp = ex.Message;
            }
        }
    }
}

运行结果:

主线程执行!2018/7/28 14:50:09
主线程结束!2018/7/28 14:50:09
线程池终止!2018/7/28 14:50:15
Begin:2018/7/28 14:50:09:第2个线程
Begin:2018/7/28 14:50:09:第3个线程
Begin:2018/7/28 14:50:09:第4个线程
Begin:2018/7/28 14:50:09:第1个线程
Begin:2018/7/28 14:50:10:第5个线程
End:2018/7/28 14:50:12:第2个线程
Begin:2018/7/28 14:50:12:第6个线程
End:2018/7/28 14:50:12:第3个线程
Begin:2018/7/28 14:50:12:第7个线程
End:2018/7/28 14:50:12:第4个线程
Begin:2018/7/28 14:50:12:第8个线程
End:2018/7/28 14:50:12:第1个线程
Begin:2018/7/28 14:50:12:第9个线程
End:2018/7/28 14:50:13:第5个线程
Begin:2018/7/28 14:50:13:第10个线程
End:2018/7/28 14:50:15:第6个线程
End:2018/7/28 14:50:15:第7个线程
End:2018/7/28 14:50:15:第8个线程
End:2018/7/28 14:50:15:第9个线程
End:2018/7/28 14:50:16:第10个线程

可以看出,线程池里线程的执行不影响主线程的运行,并且在线程池参数设置中

ThreadPool.SetMaxThreads(5, 5);

因此,先同时开始前5个线程(1-5),其它线程在排队中。然后每执行完一个线程,开始一个新的线程

End:2018/7/28 14:50:12:第2个线程
Begin:2018/7/28 14:50:12:第6个线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值