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 使用专用线程执行异步的 ...
随机推荐
- Cloning EBS from Linux 5 to Linux 6 Fails: "Error While Loading Shared Libraries: libclntsh.so.10.1
SYMPTOMS During clone Oracle Applications R12 from Linux 5 to Linux 6 the following error occurs ...
- archlinux 下 nignx + php 出现 no input file specified
奇葩的问题,配置 nginx + php + mysql 后,加一个站点: server { listen 80; server_name wei.abc.com; root /www/wei.abc ...
- js webapp 滑动事件
var startX, startY, endX, endY; $(".detailImg").on("touchstart", touchStart);$(& ...
- C#多线程管理代码
/// <summary> /// 多线程执行 /// </summary> public class MultiThreadingWorker { /// <summa ...
- raphael绘制矢量图2
最近重新再次考虑了下raphael,也没办法把公司的项目给换成raphael的渲染了.大体上的效果稍微考了下其实并不难实现,难点大多集中在对路线以及子路线和方案的转换,以及位置的确定,几乎每操作一步都 ...
- 一款基于HTML5的Web 3D开发工具
在我们协助客户进行3D应用的开发过程中,客户遇到的最头疼的问题是如何在短时间内学会使用TWaver 3D引擎,以及使用TWaver 3D来创建和导入项目所需的各种3D业务模型.由于项目涵盖的行业繁多. ...
- CommonJS 的 AMD 规范
异步模块定义(Asynchronous Module Definition,简称 AMD)API 描述了一种定义模块的机制,模块及其依赖模块可以通过这种机制进行加载.该机制特别适用于浏览器. 本规范曾 ...
- c++中继承和java中继承的对比
java中: class Parent{ public void test(int a){ System.out.println("Parent:" + a); System.ou ...
- ruby -- 进阶学习(八)自定义方法route配置
在route中进行修改,添加下面代码 namespace :mycontroller do get 'mymethod' , :on=> :member end end 注: :on => ...
- 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九-2)
作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...