C# 线程基础
1. 线程的基本概念
简单的讲进程就是程序分配在内存当中,等待处理器进行处理,请记住线程会消耗大量的操作系统资源。多个线程共享一个物理处理器将导致处理器忙于处理管理这些进程,而无法运行程序。
使用线程通常是一个操作系统的任务,试图在一个单核CPU上并行执行计算任务是没有任何意义的,可能比顺序执行花费的时间更长。
为了更好的利用现代处理器的能力,使用多线程处理程序发挥出最好的作用,这需要组织多个线程间的通讯和相互同步。
下面将学习一下 线程的生命周期,和创建线程、挂起线程、线程等待、以及终止线程。
创建一个线程操作
static void Main(string[] args)
{
//创建一个新的线程来实现输出数字
Thread t = new Thread(PrintNumber);
t.Start();
//这一行代码是在创建了一个新的线程并行执行的
PrintNumber();
Console.ReadLine();
} static void PrintNumber()
{
Console.WriteLine("Starting...");
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
}
从上面代码可以看出一个程序始终有一个主线程在执行,而Thread是创建一个新的线程执行。两者之间是同步执行的。
暂停线程
static void Main(string[] args)
{
//创建一个带暂停的进程
Thread t = new Thread(PrintNumberWithdelay);
t.Start();
//这一行就是始终执行的主线程经过(一个程序都有一个始终执行的主线程)
PrintNumber();
} static void PrintNumber()
{
Console.WriteLine("Starting...");
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
}
static void PrintNumberWithdelay()
{
Console.WriteLine("暂停...");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine(i);
}
}
很明显,主线程已经执行完毕,而新的线程在输出暂停以后还在继续执行。每次执行都会休眠2秒钟。
线程等待
那么如何不让主线程继续往下执行,而是等待新线程执行完毕再往下执行呢。
static void Main(string[] args)
{
//创建一个带暂停的进程
Thread t = new Thread(PrintNumberWithdelay);
t.Start();
t.Join();//线程等待
Console.WriteLine("执行完毕了"); }
static void PrintNumberWithdelay()
{
Console.WriteLine("暂停...");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
Console.WriteLine(i);
}
}
终止线程
static void Main(string[] args)
{
//创建一个带暂停的进程
Thread t = new Thread(PrintNumberWithdelay);
t.Start();
Thread.Sleep(TimeSpan.FromSeconds(3));
t.Abort();//终止线程
Console.WriteLine("线程终止了");
}
这段代码是给线程注入了ThreadAbortException方法,导致线程被终结,这样操作是非常危险的,因为该异常可能会导致整个应用程序都崩溃。
可以使用 ResetAbort 方法来拒绝被终止。
检测线程状态
static void Main(string[] args)
{
//创建一个带暂停的进程
Thread t = new Thread(PrintNumberWithdelay);
Thread t1 = new Thread(DoNothing);
t1.Start();
t.Start();
for (int i = 0; i < 30; i++)
{
Console.WriteLine(t.ThreadState.ToString());
}
Thread.Sleep(TimeSpan.FromSeconds(3));
t.Abort();//终止线程
Console.WriteLine("线程终止了");
Console.WriteLine(t.ThreadState.ToString());
Console.WriteLine(t1.ThreadState.ToString());
} static void PrintNumberWithdelay()
{
Console.WriteLine("开始啦...");
Console.WriteLine(Thread.CurrentThread.ThreadState.ToString());
for (int i = 0; i < 10; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(1));
Console.WriteLine(i);
}
}
static void DoNothing()
{
Thread.Sleep(TimeSpan.FromSeconds(2));
}
当主程序定义了两个不同的线程,一个将会被终止,而另一个则会成功运行。线程状态位于Thread 对象的ThreadState属性中。ThreadState属性是一个C#枚举对象。
刚开始线程状态为Unstarted ,然后启动线程,并估计在一周期为30的迭代的区间中,线程状会从Running变为WitSleepJoin。
线程优先级
class ThreadSample
{
private bool _isStopped = false;
public void Stop()
{
_isStopped = true;
}
public void CountNumbers()
{
long counter = 0;
while (!_isStopped)
{
counter++;
}
Console.WriteLine("{0} 和 {1,11}" + " count={2,13}",
Thread.CurrentThread.Name,
Thread.CurrentThread.Priority,
counter.ToString("NO"));
}
} class Program
{
static void RunThreads()
{
var sample = new ThreadSample();
var threadOne = new Thread(sample.CountNumbers);
threadOne.Name = "ThreadOne";
var threadTwo = new Thread(sample.CountNumbers);
threadTwo.Name = "ThreadTwo"; threadOne.Priority = ThreadPriority.Highest;//优先级较高
threadTwo.Priority = ThreadPriority.Lowest;//优先级较低 threadOne.Start();
threadTwo.Start(); Thread.Sleep(TimeSpan.FromSeconds(2));
sample.Stop(); }
static void Main(string[] args)
{
Console.WriteLine("线程状态:{0}",Thread.CurrentThread.Priority);
Console.WriteLine("开始");
RunThreads();
Thread.Sleep(TimeSpan.FromSeconds(3));
Console.WriteLine("模拟CPU单核计算");
//让操作系统运行在第一个CPU第一个核心上
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
RunThreads();//运行时间很长
Console.WriteLine("线程终止了");
} }
此程序只用于演示,通常中无需使用这种方式。
前台线程和后台线程
class ThreadSample
{
private readonly int _iterations;
public ThreadSample(int iterations)
{
_iterations = iterations;
}
public void CountNumbers()
{
for (int i = 0; i < _iterations; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine("{0} 和 {1}",
Thread.CurrentThread.Name, i);
} }
} class Program
{
static void Main(string[] args)
{
var samppleforegroud = new ThreadSample(10);
var sampplebackgroup = new ThreadSample(20); var threadOne = new Thread(samppleforegroud.CountNumbers); threadOne.Name = "前台"; var threadTwo = new Thread(sampplebackgroup.CountNumbers); threadTwo.Name = "后台";
threadTwo.IsBackground = true; threadOne.Start();
threadTwo.Start(); } }
显示创建的是前台线程, ThreadTwo是后台线程 ,通过配置第一个线程会比第二个线程先完成,前台线程如果执行完毕,那么也会把后台线程终止掉。
向线程传递参数
class ThreadSample
{ private readonly int _iterations;
public ThreadSample(int iterations)
{
_iterations = iterations;
}
public void CountNumbers()
{
for (int i = 0; i < _iterations; i++)
{
Thread.Sleep(TimeSpan.FromSeconds(0.5));
Console.WriteLine("{0} 和 {1}",
Thread.CurrentThread.Name, i);
} }
} class Program
{
static void Count(object i)
{
CountNumbers((int)i);
} static void CountNumbers(int number)
{
Console.WriteLine(number);
} static void PrintNumber(int number)
{
Console.WriteLine(number);
} static void Main(string[] args)
{
var samppleforegroud = new ThreadSample(10); var threadOne = new Thread(samppleforegroud.CountNumbers);
threadOne.Name = "One";
threadOne.Start();
threadOne.Join();
Console.WriteLine("------------"); var threadTwo = new Thread(Count);
threadTwo.Name = "Two";
threadTwo.Start(8);
threadTwo.Join(); var threaThree = new Thread(() => CountNumbers(12));
threaThree.Name = "Three";
threaThree.Start();
threaThree.Join(); int i = 10;
var threaFour = new Thread(() => PrintNumber(i));
i = 20;
var threaFour1 = new Thread(() => PrintNumber(i));
threaFour.Start();
threaFour1.Start(); } }
使用Lock
abstract class CountBase
{
public abstract void Increment();
public abstract void Decrement(); } class Counter : CountBase
{
public int Count { get; private set; } public override void Increment()
{
Count++;
} public override void Decrement()
{
Count--;
}
} class CounterWithLock : CountBase
{
private readonly object _syncroot = new object(); public int Count { get; private set; }
public override void Increment()
{
lock (_syncroot)
{
Count++;
}
} public override void Decrement()
{
lock (_syncroot)
{
Count--;
}
}
} class Program
{
static void TestCouner(CountBase c)
{
for (int i = 0; i < 100000; i++)
{
c.Increment();
c.Decrement();
}
} static void Main(string[] args)
{
var c = new Counter(); var t1 = new Thread(() => TestCouner(c));
var t2 = new Thread(() => TestCouner(c));
var t3 = new Thread(() => TestCouner(c)); t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join(); Console.WriteLine(c.Count); var c1 = new CounterWithLock(); t1 = new Thread(() => TestCouner(c));
t2 = new Thread(() => TestCouner(c));
t3 = new Thread(() => TestCouner(c)); t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join(); Console.WriteLine(c.Count); } }
使用Monitor 锁定资源
为了避免死锁,则使用Monitor 类 来避免死锁。
Monitor.TryEnter(lock1,TimeSpan.FromSeconds(5));
C# 线程基础的更多相关文章
- Qt之线程基础
何为线程 线程与并行处理任务息息相关,就像进程一样.那么,线程与进程有什么区别呢?当你在电子表格上进行数据计算的时候,在相同的桌面上可能有一个播放器正在播放你最喜欢的歌曲.这是一个两个进程并行工作的例 ...
- Android多线程研究(1)——线程基础及源代码剖析
从今天起我们来看一下Android中的多线程的知识,Android入门easy,可是要完毕一个完好的产品却不easy,让我们从线程開始一步步深入Android内部. 一.线程基础回想 package ...
- JAVA与多线程开发(线程基础、继承Thread类来定义自己的线程、实现Runnable接口来解决单继承局限性、控制多线程程并发)
实现线程并发有两种方式:1)继承Thread类:2)实现Runnable接口. 线程基础 1)程序.进程.线程:并行.并发. 2)线程生命周期:创建状态(new一个线程对象).就绪状态(调用该对象的s ...
- 【windows核心编程】 第六章 线程基础
Windows核心编程 第六章 线程基础 欢迎转载 转载请注明出处:http://www.cnblogs.com/cuish/p/3145214.html 1. 线程的组成 ① 一个是线程的内核 ...
- C#当中的多线程_线程基础
前言 最近工作不是很忙,想把买了很久了的<C#多线程编程实战>看完,所以索性把每一章的重点记录一下,方便以后回忆. 第1章 线程基础 1.创建一个线程 using System; usin ...
- Qt 线程基础(Thread Basics的翻译,线程的五种使用情况)
Qt 线程基础(QThread.QtConcurrent等) 转载自:http://blog.csdn.net/dbzhang800/article/details/6554104 昨晚看Qt的Man ...
- 线程基础(CLR via C#)
1.线程基础 1.1.线程职责 线程的职责是对CPU进行虚拟化.Windows 为每个进程豆提供了该进程专用的线程(功能相当于一个CPU).应用程序的代码进入死循环,于那个代码关联的进程会&quo ...
- Linux 系统应用编程——线程基础
传统多任务操作系统中一个可以独立调度的任务(或称之为顺序执行流)是一个进程.每个程序加载到内存后只可以唯一地对应创建一个顺序执行流,即传统意义的进程.每个进程的全部系统资源是私有的,如虚拟地址空间,文 ...
- python2 线程基础
1,感谢菜鸟教程, 线程基础:导入,创建函数,创建线和运行 import thread import time # 为线程定义一个函数 def print_time(threadName, delay ...
- 《CLR via C#》读书笔记 之 线程基础
第二十五章 线程基础 2014-06-28 25.1 Windows为什么要支持线程 25.2 线程开销 25.3 停止疯狂 25.6 CLR线程和Windows线程 25.7 使用专用线程执行异步的 ...
随机推荐
- winform 指定浏览器打开链接
Process myProcess = new Process(); myProcess.StartInfo.FileName = "firefox.exe";//&quo ...
- Lambda动态创建
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- VS2008简体中文正式版序列号-试用到期解决
VS2008简体中文正式版序列号 VS2008简体中文正式版序列号 1.Visual Studio 2008 Professional Edition:XMQ2Y-4T3V6-XJ48Y-D3K2V- ...
- DDD:Can I DDD?
下面是<实现领域驱动>的作者给出的一段话: You can implement DDD if you have: A passion for creating excellent soft ...
- 让服务器apache/iis/nginx支持.apk/ipa文件下载
服务器iis支持.apk文件下载的设置 IIS服务器不能下载.apk文件的原因:iis的默认MIME类型中没有.apk文件,所以无法下载. IIS服务器不能下载.apk文件的解决办法:既然.apk无法 ...
- 远程方法调用(RMI)原理与示例
RMI介绍 远程方法调用(RMI)顾名思义是一台机器上的程序调用另一台机器上的方法.这样可以大致知道RMI是用来干什么的,但是这种理解还不太确切.RMI是Java支撑分布式系统的基石,例如著名的EJB ...
- [mysql]增加用户 授权 远程登录
mysql创建用户和授权 1.创建用户: (注意:下面的指令,请在root用户下输入) CREATE USER "用户名" IDENTIFIED BY "密码" ...
- Python3.x中bytes类型和str类型深入分析
Python 3最重要的新特性之一是对字符串和二进制数据流做了明确的区分.文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示.Python 3不会以任意隐式的方式混用str和b ...
- 一起Polyfill系列:让Date识别ISO 8601日期时间格式
一.什么是ISO 8601日期时间格式 ISO 8601是国际标准化组织制定的日期时间表示规范,全称是<数据存储和交换形式·信息交换·日期和时间的表示方法>. 示例: 1. 2014-12 ...
- 2015年百度之星初赛(1) --- B 找连续数
找连续数 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...