C#中的线程之线程同步
来源:互联网 发布:调音软件哪个好 编辑:程序博客网 时间:2024/06/04 18:21
写在前面
之前写过一篇博客,C#中的线程之Abort陷阱,最近比较忙,没时间写后面的内容,恰好今天偶然看到一个技术问答。线程抢占执行怎么使10-20连续输出 。回答该问题顺便写了几个例子,于是就有了这篇博客。
问题描述
主要解决的问题是让两个线程代码能按照一定的顺序执行。题主抛出的代码是这样的:
// 需要让打印出来的结果顺序输出 static void Main(string[] args) { Thread th = new Thread(() => { for (int i = 0; i < 10; i++) { Console.WriteLine(i); Thread.Sleep(100); } }); Thread th2 = new Thread(() => { th.Join(); for (int i = 10; i < 20; i++) { Console.WriteLine(i); Thread.Sleep(100); } }); th.Start(); th2.Start(); }
输出:
10
0
1
11
12
2
13
3
14
4
15
5
16
6
17
7
8
18
9
19
问题分析
原代码中开启了两个线程,一个顺序输出0-9,另一个顺序输出10-20,由于是两个不同的线程,那么原问题就可以转换成两个线程之间的顺序执行。要实现这个功能,.NetFramework提供了很多的方法,我在此就抛砖引玉,给出几种我比较熟悉的方法。
解决方案
方案一
在初始线程的位置等待线程完成。
即在线程一执行完毕后,再开启线程二的执行。
th.Start();
th.Join();
th2.Start();
这种方法的优点是简单,缺点是不易扩展,若线程1与线程2都需要同时执行某段代码,或线程12的执行不希望影响主线程的执行。
所以我们一定还有更好的方法实现这样的效果
方案二
在线程二执行时等待。
即在线程二开启后,等待线程一的完成。代码如下:
static void Main(string[] args) { Thread th = new Thread(() => { for (int i = 0; i < 10; i++) { Console.WriteLine(i); Thread.Sleep(100); } }); Thread th2 = new Thread(() => { th.Join(); for (int i = 10; i < 20; i++) { Console.WriteLine(i); Thread.Sleep(100); } }); th.Start(); th2.Start(); Console.WriteLine("线程启动完毕!"); }
此方法的优点正好弥补了方案一的缺点,但它的缺点是我们必须知道线程1的实例。这在实际项目中有可能就很麻烦了,
如果有10个这样的线程需要进行同步执行。那10个线程都需要知道上一个线程的实例,并在自己的线程中等待。
这样写代码是难以读懂并维护的。就着代码简洁的原则,我们也需要考虑其它的实现方式。
方案三
使用锁来实现。代码如下:
static void Main(string[] args) { object ThreadLocker =new object(); Thread th = new Thread(() => { lock (ThreadLocker) { for (int i = 0; i < 10; i++) { Console.WriteLine(i); Thread.Sleep(100); } } }); Thread th2 = new Thread(() => { lock (ThreadLocker) { for (int i = 10; i < 20; i++) { Console.WriteLine(i); Thread.Sleep(100); } } }); Thread th3 = new Thread(() => { lock (ThreadLocker) { for (int i = 20; i < 30; i++) { Console.WriteLine(i); Thread.Sleep(100); } } }); th.Start(); while (th.ThreadState != ThreadState.Running) { //Console.WriteLine("等待线程1执行"); } th2.Start(); while (th2.ThreadState != ThreadState.Running) { //Console.WriteLine("等待线程2执行"); } th3.Start(); while (th3.ThreadState != ThreadState.Running) { //Console.WriteLine("等待线程3执行"); } Console.WriteLine("线程启动完毕!"); }
线程锁来决定对资源的互斥,注意代码中在主线程中用while判断线程的状态是为了达到线程顺序启动的目的(因为在多核的情况下,线程的执行顺序是不确定的)。
注意这里开了三个线程,在while等待的时候我起初准备使用Console.WriteLine来打印确定时序,实际发现这样并不能精准反映时序。因为这里涉及到Console.WriteLine的线程安全问题,
此问题不在本题讨论范围内,可以考虑使用System.Diagnostics.Debug.WriteLine在调试状态下查看输出窗口。
还有个要注意的是: 主线程的执行还是会阻塞!虽然只有很少的时间,若主线程少量阻塞不影响程序的功能,那这种方法是可行的,但若对要求较高,那我们还得考虑其它方法。
方案四
使用信号量,信号量也是常用的线程同步方案之一。
static void Main(string[] args) { int iThreadNum = 3; AutoResetEvent[] evts = new AutoResetEvent[iThreadNum]; for (int i = 0; i < iThreadNum; i++) { evts[i] = new AutoResetEvent(false); } Thread th = new Thread(() => { for (int i = 0; i < 10; i++) { Console.WriteLine(i); Thread.Sleep(100); } evts[0].Set(); }); Thread th2 = new Thread(() => { evts[0].WaitOne(); for (int i = 10; i < 20; i++) { Console.WriteLine(i); Thread.Sleep(100); } evts[1].Set(); }); Thread th3 = new Thread(() => { evts[1].WaitOne(); for (int i = 20; i < 30; i++) { Console.WriteLine(i); Thread.Sleep(100); } }); th3.Start(); th2.Start(); th.Start(); Console.WriteLine("线程启动完毕!"); }
使用信号量其实与第二种方法有些类似,不过这种方式更加灵活,不用等到线程结束。
总结
好了,我要说的就这么多了,.NetFramework作为一个比较成熟的技术提供的线程同步方案特别多,若有兴趣建议多查查文档。在文档里我们能收获很多东西。
ps:本文中的代码只看懂测试,实际这样写代码我是会很生气的!
- C#中的线程之线程同步
- C#中的线程同步
- C#中的线程(二) 线程同步基础
- C#中的线程(二)线程同步
- C#中的线程(二)线程同步
- C#中的线程(二) 线程同步基础
- C#中的线程(中)-线程同步
- C#中的线程(二) 线程同步基础
- C#中的线程(二) 线程同步基础
- C#中的线程(二) 线程同步基础
- C#中的线程(二) 线程同步基础
- C# 线程同步之Monitor
- C#之线程同步方法
- C#中的线程 -- 同步基础(线程状态,同步上下文)
- 线程之线程同步
- C#中的几个线程同步对象
- C#中的几个线程同步对象方法
- c#中的线程同步或者异步问题
- 101-200
- WSGI:简介
- ActiveMQ高可用架构(zookeeper+levelDB)
- Ubuntu linux中切换到超级用户的方法
- 201-300
- C#中的线程之线程同步
- 写一个宏函数交换一个数字的偶数比特位和奇数比特位
- 301-400
- Python实现抓取链接/分词/索引/搜索关键词——简单搜索引擎
- 什么情况下会导致内存泄露
- android新建工程报找不到android:preserveIconSpacing的错误
- 401-500
- C++多态
- 501-600