博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#多线程基础
阅读量:4921 次
发布时间:2019-06-11

本文共 4422 字,大约阅读时间需要 14 分钟。

最近花了近两周时间读完了C#本质论,这本书非常喜欢,但是到后面关于多线程和同步这块,读起来就感觉有些困难了,所以做了笔记,一方面防止忘记,另一方法如果有不正确的地方,十分欢喜各位前辈不吝赐教

什么是单线程

通过一个控制台程序来认识单线程

static void Main(string[] args){    var mainThread = Thread.CurrentThread;}

在Console.WriteLine处添加一个断点,查看主线程属性

ApartmentSate:msdn的大致意思,相同对单元状态的线程之间可以相互访问对象,然而在.net中由clr以线程安全的方式管理所有共享资源

CurrentCulture和CurrentUICulture表示区域信息

ExecutionContext:封装线程相关的上下文信息

IsAlive:如果此线程已启动并且尚未正常终止或中止,则为 true;否则为 false

IsBackground:表示是否是后台线程

IsThreadPoolThread:表示是否是线程池线程

ManagedThreadId:托管线程的唯一标识符

更多可查msdn

小结:

关于线程的定义很多地方都有的,我想举一个例子,很多时候,我们人就是一个线程,早上起床,吃早饭,上班,下班......这一系列事情有序执行就是一个单线程,但是有的时候,一边听歌,一边看小说实际上就开启了第二个线程了,假如此时再写代码,那就是开启第三个线程了

使用Thread创建一个线程

const int Repetitions = 100;static void Main(string[] args){    ThreadStart threadStart = DoWork;    Thread thread = new Thread(threadStart);    thread.Start();    //Main线程启动一个循环    for (int count = 0; count < Repetitions; count++)    {        Console.Write('-');    }    Console.WriteLine("(主线程最后一个语句...)");}static void DoWork(){    for (int count = 0; count < Repetitions; count++)    {        Console.Write("+");    }}

Ctrl+F5运行,可以看到,新创建的线程和Main线程中的循环是同步执行的(多启动几次,会有不一样的发现哦!)

那么问题来了,我们创建的线程执行完了吗?程序到底什么时候结束?为什么主线程最后一句话执行完了,创建的线程还在控制台输出?

修改一下程序,Ctrl+F5,多启动几次,会有不一样的发现哦!

const int Repetitions = 100;static int index_thread = 0;static int index_main = 0;static void Main(string[] args){    ThreadStart threadStart = DoWork;    Thread thread = new Thread(threadStart);    thread.Start();    //Main线程启动一个循环    for (int count = 0; count < Repetitions; count++)    {        index_main++;        Console.Write('-');    }    Console.WriteLine($"\nindex_thread:{index_thread}");    Console.WriteLine($"index_main:{index_main}");    Console.WriteLine("(主线程最后一个语句...)");}static void DoWork(){    for (int count = 0; count < Repetitions; count++)    {        index_thread++;        Console.Write("+");        if (count == Repetitions - 1)        {            Debug.Write("我创建的线程执行完成了.....................................\n");        }    }}

假如你是直接按F5,可以在Visual Studio输出栏看到

结论:

1.操作系统在所有前台线程(主线程和新创建的线程都是前台线程)结束后终止进程,虽然在控制台中输出的index_thread不总是100

2.主线程以外的线程执行情况是不确定的,

3.实际上,主线程会等待所有子线程(前台线程)结束后,结束主线程,关闭进程,结束程序

4.由于子主线程执行情况的不确定性,在主线程输出index_thread的时候,可能子线程循环结束了,也可能没结束,所以导致结果总是不为100

通过Join方法阻塞主线程,等待子线程执行结束

//省略部分代码thread.Join();Console.WriteLine($"\nindex_thread:{index_thread}");

这样,就可以保证在此之后,子线程已经运行结束了,每次输出的结果都为100

使用线程池

const int Repetitions = 1000;static int index_thread = 0;static int index_main = 0;static void Main(string[] args){    WaitCallback waitCallBack = DoWork;    ThreadPool.QueueUserWorkItem(waitCallBack, '+');    //Main线程启动一个循环    for (int count = 0; count < Repetitions; count++)    {        index_main++;        Console.Write('-');    }    Console.WriteLine($"\nindex_thread:{index_thread}");    Console.WriteLine($"index_main:{index_main}");    Console.WriteLine("主线程最后一个语句");}private static void DoWork(object ch){    for (int count = 0; count < Repetitions; count++)    {        index_thread++;        Console.Write(ch);        if (count == Repetitions - 1)        {            Debug.Write("我创建的线程执行完成了.....................................\n");        }    }}

优点:

1.解决线程太多造成的性能方面的负面影响

2.高效的利用处理器

2.结合lambda使用委托,代码可以更精简

注意点

1.使用线程池创建的线程都是后台线程

2.不要使用线程池运行时间特别长的任务,尽量不要I/O受限

异步任务

static void Main(string[]  args){    Task task = Task.Run(()        =>    {        var t = Thread.CurrentThread;        for (int count = 0; count < Repetitions; count++)        {            index_thread++;            Console.Write('+');        }    });    for (int count = 0; count < Repetitions; count++)    {        index_main++;        Console.Write('-');    }    //类似THread.Join方法    task.Wait();    Console.WriteLine($"\nindex_thread:{index_thread}");    Console.WriteLine($"index_main:{index_main}");    Console.WriteLine("Over");    Console.ReadLine();}

Task是.Net Framwwork4引入的一个类库,它在使用上比Thread简单了,可控性又THreadPool强了,默认情况下,它也是从线程池中请求一个线程来执行任务.

与ThreadPool相同的是,当创建时(调用Run)启动,与Thread相同的是,可以通过Wait()方法阻塞上下文线程(主线程)等待任务执行完成

带返回值的异步任务

static void Main(string[] args){    Task
task = Task.Run(() => "string 类型 返回值"); for (int i = 0; i < 1000; i++) { if (task.IsCompleted) { Console.Write('任务完成了'); break; } Console.Write('.'); } Console.WriteLine(task.Result);}

泛型的Task表示该任务具有返回值,IsCompleted表示任务是否完成

要注意的是,调用Result属性的时候,会阻塞上下文进程(内部执行Wait())

转载于:https://www.cnblogs.com/cheesebar/p/6549656.html

你可能感兴趣的文章
Linux系统通过AWS命令行上传文件至S3
查看>>
FlashFXP 上传文件错误
查看>>
Delphi 的内存操作函数(2): 给数组指针分配内存
查看>>
三款SDR平台对比:HackRF,bladeRF和USRP
查看>>
通过js获得html标签的值
查看>>
Sqoop 1.4.7安装与配置
查看>>
浅谈数据库资源使用的按需分配方法
查看>>
linux运维面试题1
查看>>
fabric网关模式文件上传与执行
查看>>
转:一千行 MySQL 学习笔记
查看>>
hadoop控制map个数(转)
查看>>
SVProgressHUD 用法
查看>>
【BZOJ】【1046】/【POJ】【3613】【USACO 2007 Nov】Cow Relays 奶牛接力跑
查看>>
Django表单
查看>>
ini 文件操作记要(2): 使用 TMemIniFile
查看>>
(第3篇)HDFS是什么?HDFS适合做什么?我们应该怎样操作HDFS系统?
查看>>
隐藏 DataGrid 中 DataSource 为 DataTable 的 DataColumn (Visual C#)
查看>>
【译 】Solr in Action 第一章
查看>>
计算几何初步模板
查看>>
POJ 数据结构(2)
查看>>