Thread
先说一下基础定义:
线程
被定义为程序的执行路径。每个线程都定义了一个独特的控制流。如果您的应用程序涉及到复杂的和耗时的操作,那么设置不同的线程执行路径往往是有益的,每个线程执行特定的工作。
线程是轻量级进程。一个使用线程的常见实例是现代操作系统中并行编程的实现。使用线程节省了 CPU 周期的浪费,同时提高了应用程序的效率。
线程的生命周期:
线程生命周期开始于 System.Threading.Thread 类的对象被创建时,结束于线程被终止或完成执行时。
下面列出了线程生命周期中的各种状态:
- 未启动状态:当线程实例被创建但 Start 方法未被调用时的状况。
- 就绪状态:当线程准备好运行并等待 CPU 周期时的状况。
- 不可运行状态:下面的几种情况下线程是不可运行的:
- 已经调用 Sleep 方法
- 已经调用 Wait 方法
- 通过 I/O 操作阻塞
- 死亡状态:当线程已完成执行或已中止时的状况。
主线程
在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程。
当 C# 程序开始执行时,主线程自动创建。使用 Thread 类创建的线程被主线程的子线程调用。您可以使用 Thread 类的 CurrentThread属性访问线程。
Thread 类常用的属性和方法
属性 | 描述 |
---|---|
CurrentContext | 获取线程正在其中执行的当前上下文。 |
CurrentCulture | 获取或设置当前线程的区域性。 |
CurrentPrinciple | 获取或设置线程的当前负责人(对基于角色的安全性而言)。 |
CurrentThread | 获取当前正在运行的线程。 |
CurrentUICulture | 获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源。 |
ExecutionContext | 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。 |
IsAlive | 获取一个值,该值指示当前线程的执行状态。 |
IsBackground | 获取或设置一个值,该值指示某个线程是否为后台线程。 |
IsThreadPoolThread | 获取一个值,该值指示线程是否属于托管线程池。 |
ManagedThreadId | 获取当前托管线程的唯一标识符。 |
Name | 获取或设置线程的名称。 |
Priority | 获取或设置一个值,该值指示线程的调度优先级。 |
ThreadState | 获取一个值,该值包含当前线程的状态。 |
大水法
下面看一些问题
1、为什么我设置了多线程的优先级,可是线程的输出并不是按优先级的高低输出啊?
看如下代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace _05线程的优先级 { class Program { static void Main(string[] args) { Thread[]t = new Thread[5]; t[0] =new Thread( new ThreadStart(Tell)); t[0].Name = "Lowest"; t[0].Priority = ThreadPriority.Lowest; t[1] = new Thread(new ThreadStart(Tell)); t[1].Name = "BelowNormal"; t[1].Priority = ThreadPriority.BelowNormal; t[2] = new Thread(new ThreadStart(Tell)); t[2].Name = "Normal"; t[3] = new Thread(new ThreadStart(Tell)); t[3].Name = "AboveNormal"; t[3].Priority = ThreadPriority.AboveNormal; t[4] = new Thread(new ThreadStart(Tell)); t[4].Name = "Highest"; t[4].Priority = ThreadPriority.Highest; foreach (Thread itemt in t) { itemt.Start(); } Console.ReadLine(); } public static void Tell() { Console.WriteLine("当前线程为:{0},线程级别是{1}",Thread.CurrentThread.Name,Thread.CurrentThread.Priority); } } }
运行结果之一:
首先,解释一下线程的优先级:
线程的优先级并不是你想象的先执行哪个后执行哪个
而是所有的线程不论优先级高低都会执行,
优先级越高表示CPU分配给该线程的时间片越多,执行时间就多
优先级越低表示CPU分配给该线程的时间片越少,执行时间就少
就这个问题我们可以做一些测试,看如下代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace _05线程的优先级_测试线程优先级发生概率 { class Program { static void Main(string[] args) { Thread th1 = new Thread(delegate() { for (int i = 0; i < 100; i++) { Console.Write("H"); } }); // th1.Priority = ThreadPriority.Highest; Thread th2 = new Thread(delegate() { for (int i = 0; i < 100; i++) { Console.Write("A"); } } ); // th2.Priority = ThreadPriority.AboveNormal; Thread th3 = new Thread(delegate() { for (int i = 0; i < 100; i++) { Console.Write("N"); } } ); // th3.Priority = ThreadPriority.Normal; Thread th4 = new Thread(delegate() { for (int i = 0; i < 100; i++) { Console.Write("B"); } } ); // th4.Priority = ThreadPriority.BelowNormal; Thread th5 = new Thread(delegate() { for (int i = 0; i < 100; i++) { Console.Write("L"); } } ); // th5.Priority = ThreadPriority.Lowest; th1.Start(); th2.Start(); th3.Start(); th4.Start(); th5.Start(); Console.ReadKey(); } } }
运行结果之一:
将注释代码取消注释,运行结果之一:
总结一句话就是:我们给线程分配优先级增加或减少的是该线程被优先执行的概率:
ThreadPool
static void Main(string[] args) { //打印当前线程ID Console.WriteLine("Main threading"+Thread.CurrentThread.ManagedThreadId); //调用线程池中的线程,将方法插入队列 for (int i = 0; i < 8; i++) { //线程池线程执行的回调方法 ThreadPool.QueueUserWorkItem(new WaitCallback(new Program().Show), "OK"); } Console.ReadKey(); } public void Show(object s) { Console.WriteLine("ThreadPool's thread,number is"+s.ToString()+" "+Thread.CurrentThread.ManagedThreadId); }
当我们想绝对控制一个线程时单独创建线程,一般就用线程池交于系统分配
ObjectPool
namespace 对象池_线程池技术 { class Program { /// <summary> /// 模拟一个生产者消费者的对象池 /// 具体情景:池子的容量是100,生产者向池子里生产产品,当产品个数小于0或者大于100时继续生产但是不添加到 /// 池子里面去;当池子中有产品时,消费者开始消费产品,消费者消费是从底端开始的;采用锁机制是因为当消费 /// 正在消费完第8个产品时,生产者生产完第9个产品,该产品应放在原来第8号产品的位置,但此时index没有被更 /// 新,所以对对象锁定 /// </summary> /// <param name="args"></param> static void Main(string[] args) { //1、首先定义一个对象池 MyPool[]myPools=new MyPool[100]; //2、定义一个游标 int index = 0; //3、声明一个对象 Program program = new Program(); //4、定义生产者线程 #region 生产者线程 for (int i = 0; i < 100; i++) { Thread threadProducer = new Thread( () => { while (true) { lock (program) { //声明对象 MyPool myPool = new MyPool(); //进行判断 if (index >= 100 || index < 0) { continue;//继续生产 } //将生产的对象添加到对象池中 myPools[index] = myPool; //对象索引增加 index++; //打印当前生产的产品的所在线程 Console.WriteLine("生产者生产一个产品,该产品所在线程是:{0}", Thread.CurrentThread.ManagedThreadId); } //生产一次休息1秒-1秒之类生产者可能生产了好几个,设置的时间不同产生的效果也就不一样 Thread.Sleep(TimeSpan.FromSeconds(1)); } } ); //设置为后台线程 threadProducer.IsBackground = true; //启动该线程 threadProducer.Start(); } #endregion for (int j = 0; j < 100; j++) { //声明消费者线程 Thread threadConsumer = new Thread( () => { while (true) { lock (program) { if (index <= 0) { continue;//继续消费 } //当生产者线程执行一次之后index++,此时该index++的产品还未生产出来,消费者执行时index已经加了1,所以对应的应该减1 myPools[index - 1] = null; index--; //打印消线程费 Console.WriteLine("消费者消费掉了一个产品,该消费者线程是:{0}", Thread.CurrentThread.ManagedThreadId); } //消费一个产品休息1秒钟 Thread.Sleep(TimeSpan.FromSeconds(1)); } } ); //后台线程 threadConsumer.IsBackground = true; //开始执行消费者线程 threadConsumer.Start(); } Console.ReadKey(); } } public class MyPool { public string Name { get; set; }//名字 } }
其中用到了lock锁,锁住的是同一个对象,不然不是同一个锁,需要提醒一下的是lock锁定的是引用类型对象,当然你也可以锁定值类型,不过需要装箱转换成object类型,装箱后再分配内存地址,有时候会想能否锁定字符串,当然可以锁定,但是会出问题,字符串是全局变量,比如说锁定了lock("a"),那么你能保证这个字符串不会再出现在你程序的其他地方吗?
Process
1、Start a process
static void Main(string[] args) { //开启一个新的进程 Process process = Process.Start("iexplore.exe","http://www.baidu.com"); //打印该进程的标识符Id Console.WriteLine(process.Id); Console.ReadKey(); }
2、Foreach all processes
#region Foreach processes //获取当前计算机的线程 Process[] allProcess = Process.GetProcesses(); //遍历所有线程 foreach (var process in allProcess) { //打印线程的ID和Name Console.WriteLine(process.Id + " : " + process.ProcessName); } Console.ReadKey(); #endregion
3、Kill CurrentProcess
//kill掉当前线程 Process.GetCurrentProcess().Kill();
在操作office的时候会弹出excel、word等进程,这时候就需要考虑将其kill掉
private void KillExcel() { try { System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcesses(); foreach (System.Diagnostics.Process process in processes) { if (process.ProcessName.ToLower().Equals("excel")) { process.Kill(); } } } catch (Exception exception) { exception.Message.ToString(); } }
AppDomain
一个进程中含有好几个应用程序域=》每个应用程序域中可以执行多个线程=》对于另外开辟的线程,同一时间只能在一个应用程序域中执行,如下是传智播客教程截图,该很容易懂吧