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# 线程基础的更多相关文章

  1. Qt之线程基础

    何为线程 线程与并行处理任务息息相关,就像进程一样.那么,线程与进程有什么区别呢?当你在电子表格上进行数据计算的时候,在相同的桌面上可能有一个播放器正在播放你最喜欢的歌曲.这是一个两个进程并行工作的例 ...

  2. Android多线程研究(1)——线程基础及源代码剖析

    从今天起我们来看一下Android中的多线程的知识,Android入门easy,可是要完毕一个完好的产品却不easy,让我们从线程開始一步步深入Android内部. 一.线程基础回想 package ...

  3. JAVA与多线程开发(线程基础、继承Thread类来定义自己的线程、实现Runnable接口来解决单继承局限性、控制多线程程并发)

    实现线程并发有两种方式:1)继承Thread类:2)实现Runnable接口. 线程基础 1)程序.进程.线程:并行.并发. 2)线程生命周期:创建状态(new一个线程对象).就绪状态(调用该对象的s ...

  4. 【windows核心编程】 第六章 线程基础

    Windows核心编程 第六章 线程基础 欢迎转载 转载请注明出处:http://www.cnblogs.com/cuish/p/3145214.html 1. 线程的组成 ①    一个是线程的内核 ...

  5. C#当中的多线程_线程基础

    前言 最近工作不是很忙,想把买了很久了的<C#多线程编程实战>看完,所以索性把每一章的重点记录一下,方便以后回忆. 第1章 线程基础 1.创建一个线程 using System; usin ...

  6. Qt 线程基础(Thread Basics的翻译,线程的五种使用情况)

    Qt 线程基础(QThread.QtConcurrent等) 转载自:http://blog.csdn.net/dbzhang800/article/details/6554104 昨晚看Qt的Man ...

  7. 线程基础(CLR via C#)

    1.线程基础  1.1.线程职责  线程的职责是对CPU进行虚拟化.Windows 为每个进程豆提供了该进程专用的线程(功能相当于一个CPU).应用程序的代码进入死循环,于那个代码关联的进程会&quo ...

  8. Linux 系统应用编程——线程基础

    传统多任务操作系统中一个可以独立调度的任务(或称之为顺序执行流)是一个进程.每个程序加载到内存后只可以唯一地对应创建一个顺序执行流,即传统意义的进程.每个进程的全部系统资源是私有的,如虚拟地址空间,文 ...

  9. python2 线程基础

    1,感谢菜鸟教程, 线程基础:导入,创建函数,创建线和运行 import thread import time # 为线程定义一个函数 def print_time(threadName, delay ...

  10. 《CLR via C#》读书笔记 之 线程基础

    第二十五章 线程基础 2014-06-28 25.1 Windows为什么要支持线程 25.2 线程开销 25.3 停止疯狂 25.6 CLR线程和Windows线程 25.7 使用专用线程执行异步的 ...

随机推荐

  1. iTunes Connect突然登录不了的原因

    突然使用开发者账号登录不了iTunes Connect了,提示:Your Apple ID or password was entered incorrectly. 这是由于iTunes Connec ...

  2. JsonView Tool

  3. 近期Windows 10 RedStone 2 Insider版本安装进度停留在百分之23、24解决方案

    近期安装Windows 10 RedStone 2的14965.14971会出现停留在23%或者24%的现象,解决办法是拔掉扩展的SD卡再重新安装.

  4. div 等高

    padding-bottom: 5000px; margin-bottom: -5000px;

  5. zepto - reduce

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce var ss ...

  6. 通过IIS不能连接远程数据库的问题

    近期遇到一个奇怪的问题:在调试MES程序时发现,如果连接的是远程的SQL SERVER数据库(通过了IIS),则提示连接失败,就是经常见到的数据库不允许远程连接的错误提示: 而且又测试了以下几种情况: ...

  7. vs2010设置

    解决方案管理器文件自动定位:工具--选项--项目和解决方案--常规--在解决方案资源管理器中跟踪活动项(前打勾). VAssistX拼写错误的下划波浪线去掉:在VAssistX菜单栏->Visu ...

  8. eclipse开发web应用程序步骤(图解)

    *运行环境(也就是服务器的选择) 环境搭建好之后开始编写web程序!然后右键->Run as -> Run on Server!

  9. Web离线存储的几种方式

    随着HTML5的正式定稿,我们也可以大量使用HTML离线网络应用程序的特性. #1.Application Cache Application Cache 可以很简单让我们的WebApp具有离线的能力 ...

  10. Web压力测试 ApacheBench(ab)

    ApacheBench命令原理 ab命令会创建很多的并发访问线程,模拟多个访问者同时对某一URL地址进行访问.它的测试目标是基于URL的,因此,既可以用来测试Apache的负载压力,也可以测试ngin ...