C#学习随手笔记之多线程编程

本文详细介绍了C#中的多线程编程,包括线程的概念、优缺点、线程同步、线程池和Task的使用。强调了线程同步的重要性,通过示例解释了Lock的使用,并提醒了Lock的潜在问题。还探讨了Task和async/await在异步编程中的应用,以及如何取消和管理Task。最后提到了ManualResetEvent在线程同步中的作用。
摘要由CSDN通过智能技术生成
线程的概念:

线程(Thread)是进程中的基本执行单元,是操作系统分配CPU时间的基本单位,一个进程可以包含若干个线程,在进程入口执行的第一个线程被视为这个进程的主线程。在.NET应用程序中,都是以Main()方法作为入口的,当调用此方法时系统就会自动创建一个主线程。线程主要是由CPU寄存器、调用栈和线程本地存储器(Thread Local Storage,TLS)组成的。CPU寄存器主要记录当前所执行线程的状态,调用栈主要用于维护线程所调用到的内存与数据,TLS主要用于存放线程的状态信息。(即线程是CPU调度的基本单位)

多线程的优缺点:

当前CPU运行速度太快,硬件处理速度跟不上,所以操作系统进行分时间片管理。这样,从宏观角度来说是多线程并发的,因为CPU速度太快,察觉不到,看起来是同一时刻执行了不同的操作。但是从微观角度来讲,同一时刻只能有一个线程在处理。(单核CPU情况),所以对于使用多线程来处理,能够是程序执行更加高效,并且能够实现并发量。但是在使用多线程时候,并不是越多越好,频繁的去创建多线程容易造成内存的损耗,当要并发的代码段十分简单,创建多个线程需要进行上下文切换等,并不会比单个线程块
所以说线程是一把双刃剑。如:
(1)线程也是程序,所以线程需要占用内存,线程越多,占用内存也越多。

(2)多线程需要协调和管理,所以需要占用CPU时间以便跟踪线程。

(3)线程之间对共享资源的访问会相互影响,必须解决争用共享资源的问题。

(4)线程太多会导致控制太复杂,最终可能造成很多程序缺陷。

C#中的多线程编程

一、在默认的情况下,C#程序具有一个线程,此线程执行程序中以Main方法开始和结束的代码,Main()方法直接或间接执行的每一个命令都有默认线程(主线程)执行,当Main()方法返回时此线程也将终止。

二、在C#中,线程是使用Thread类处理的,该类在System.Threading命名空间中。使用Thread类创建线程时,只需要提供线程入口,线程入口告诉程序让这个线程做什么。通过实例化一个Thread类的对象就可以创建一个线程。创建新的Thread对象时,将创建新的托管线程。Thread类接收一个ThreadStart委托或ParameterizedThreadStart委托的构造函数。且有参的委托其参数类型必须为object类型

 //C#创建多线程,可以使用静态成员方法,也可以使用成员方法。
            MyThread mythread = new MyThread();
            Thread th1 = new Thread(new ThreadStart(mythread.TestThreadFunc2));
            Thread th2 = new Thread(new ThreadStart(MyThread.TestThreadFunc1));
            Thread th3 = new Thread(new ParameterizedThreadStart(mythread.TestThreadFunc3));

            th1.Start();
            th2.Start();
            th3.Start("parame");
            Console.ReadLine();
        }

        class MyThread
        {
   
            public static void TestThreadFunc1()
            {
   
                for(int i = 0; i < 5; i++)
                {
   
                    Console.WriteLine("I am a static func thread......");
                }
            }

            public void TestThreadFunc2()
            {
   
                for(int i = 0; i < 5; i++)
                {
   
                    Console.WriteLine("I am a sample func thread....");
                }
            }

            public void TestThreadFunc3(object name )
            {
   
                for(int i = 0; i < 5; i++)
                {
   
                    Console.WriteLine("I am a param func thread....{0}", name);
                }
            }
        }
线程中常用的属性
属性 说明
CurrentContext 获取线程正在其中执行的当前上下文。
CurrentThread 获取当前正在运行的线程。
ExecutionContext 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
IsAlive 获取一个值,该值指示当前线程的执行状态。
IsBackground 获取或设置一个值,该值指示某个线程是否为后台线程。
IsThreadPoolThread 获取一个值,该值指示线程是否属于托管线程池。
ManagedThreadId 获取当前托管线程的唯一标识符。
Name 获取或设置线程的名称。
Priority 获取或设置一个值,该值指示线程的调度优先级。
ThreadState 获取一个值,该值包含当前线程的状态。
相关属性说明
  • ManagedThreadId是确认线程的唯一标识符,程序在大部分情况下都是通过Thread.ManagedThreadId来辨别线程的。而Name是一个可变值,在默认时候,Name为一个空值 Null,开发人员可以通过程序设置线程的名称,但这只是一个辅助功能。
  • .NET为线程设置了Priority属性来定义线程执行的优先级别,里面包含5个选项,其中Normal是默认值。除非系统有特殊要求,否则不应该随便设置线程的优先级别。分别为Lowest、BelowNormal、Normal、AboveNormal、Highest。
  • ThreadState可以检测线程是处于Unstarted、Sleeping、Running 等等状态,它比 IsAlive 属性能提供更多的特定信息。一个应用程序域中可能包括多个上下文,而通过CurrentContext可以获取线程当前的上下文。
    当一个线程执函数执行完毕之后,其状态为Stopped,当其时间片未被分配为WaitSleepJoin状态。在这里插入图片描述
  • CurrentThread是最常用的一个属性,它是用于获取当前运行的线程的属性,包括线程ID,并且封装内存槽保存本地数据等。
  • IsBackground,设置前台后台线程。通过代码可以直观的看出。
mythread1.Count = 10;
            mythread2.Count = 20;
            Thread frontThread = new Thread(new ThreadStart(mythread1.RunLoop));
            frontThread.Name = "前台线程";
            Thread backThread = new Thread(new ThreadStart(mythread2.RunLoop));
            backThread.Name = "后台线程";
            backThread.IsBackground = true;

            backThread.Start();
            frontThread.Start();
        }

        class MyThread
        {
   
            public int Count {
    get; set; }
            public void RunLoop()
            {
   
                string threadName = Thread.CurrentThread.Name;
                for(int i = 0; i < Count; i++)
                {
   
                    Console.WriteLine("{0} Count : {1}", threadName, i);
                }
            }
        }

在这里插入图片描述
可以看到,后台程序没有执行完,程序就结束运行了。当我们把isBackground注释掉(默认的都为前台进程)。
在这里插入图片描述
程序需要等待所有前台线程执行完才结束。后台线程一般用于处理不重要的事情,应用程序结束时,后台线程是否执行完成对整个应用程序没有影响。如果要执行的事情很重要,需要将线程设置为前台线程。

线程类的方法
方法名 功能
Abort() 终止本线程
GetDomain() 返回当前线程正在其中运行的当前域。
GetDomainId() 返回当前线程正在其中运行的当前域Id。
Interrupt() 中断处于 WaitSleepJoin 线程状态的线程。
Join() 已重载。 阻塞调用线程,直到某个线程终止时为止。
Resume() 继续运行已挂起的线程。
Start() 执行本线程。
Suspend() 挂起当前线程,如果当前线程已属于挂起状态则此不起作用
Sleep() 把正在运行的线程挂起一段时间。

下面对Interrupt函数进行代码演示。


            sleeper = new Thread(new ThreadStart(SleepThread));
            interrupter = new Thread(new ThreadStart(InterruptThread));

            sleeper.Start();
            interrupter.Start();
            

        }
        public static Thread sleeper;
        public static Thread interrupter;
        static public void SleepThread()
        {
   
            for(int i = 0; i < 50; i++
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值