拓展方法
声明和使用
class Program { static void Main(string[] args) { int num = 10; Console.WriteLine(num.Test1()); //调用必须是变量名.拓展方法 } } static public class Test //必须是静态类 { public static string Test1(this int a) //必须是静态方法,第一个参数必须以this修饰 而且是要拓展的类型 { return Convert.ToString(a + "b"); } }
练习:把一个uint数字转成该数字的二进制输出
class Program { static void Main(string[] args) { uint num = 4; Console.WriteLine(num.Change()); } } static public class Binary { static public uint Change(this uint num) { Stack stack1 = new Stack(); while(num!=0) { stack1.Push(num % 2); //数字对2取余放入栈中 num /= 2; //数字除以2 进入下一次循环 } Console.WriteLine("111"); string a = ""; int n = stack1.Count; //遍历栈可以用count查询元素个数 然后遍历 for (int i = 0; i < n; i++) { a += stack1.Pop(); } Console.WriteLine(a); return Convert.ToUInt32(a); } }
多线程
进程
进程是资源(CPU、内存等)分配的基本单位
对于操作系统来说,一个任务可以理解为一个进程,程序运行时就会创建一个进程
线程
一个进程至少包含一个线程(主线程)
可以包含很多个子线程
所有的线程共享一个进程的所有资源,所以多线程要避免死锁
多线程
在一个进程中,除了主线程外,还有其他的子线程,那么就是一个多线程的任务
创建和启动
static void Main(string[] args) { Thread t = new Thread(Test); Thread t2 = new Thread(Test2); t.Start(); t2.Start(); Console.WriteLine("主线程"); } static void Test() { for (int i = 0; i < 10; i++) { Console.WriteLine("子线程11111"); } } static void Test2() { for (int i=0;i<10;i++) { Console.WriteLine("子线程22222"); } }
结果:
注意
参数传递
使用Thread开启多线程,当方法需要传递参数时,只能使用Object类型
线程征用
多个线程同时去访问一个变量的时候,就会发生数据的争用
class MyT { int num = 10; public void ChangeState() { num++; if(num==10) { Console.WriteLine("num值是10;"); //正常情况下 这条语句永远无法执行 } num = 10; } } class Program { static void Main(string[] args) { MyT m = new MyT(); //实例化MyT类 Thread t1 = new Thread(Change); //创建第一个多线程 Thread t2 = new Thread(Change); //创建第二个子线程 t1.Start(m); //开启字线程 把m传递过去 t2.Start(m); } static void Change(object o) //多线程传值只能是object 而且只能传递一个值 { MyT n = o as MyT; //object类型转换成MyT类型 while(true) { n.ChangeState(); } } }
结果:
解决办法:加锁:Lock
lock(要锁的数据) { }
static void Change(object o) //多线程传值只能是object 而且只能传递一个值 { MyT n = o as MyT; //object类型转换成MyT类型 while(true) { lock(n) { n.ChangeState(); } } }
效果:
死锁
概念
死锁是两个或更多线程阻塞着等待其它处于死锁状态的线程所持有的锁。
死锁通常发生在多个线程同时但以不同的顺序请求同一组锁的时候
死锁的原因
互斥条件:一个资源每次只能被一个线程使用。
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
static object o1 = new object(); static object o2 = new object(); static int count = 0; static void Main(string[] args) { Thread t1 = new Thread(Test1); Thread t2 = new Thread(Test2); t2.Start(); t1.Start(); } static void Test1() { while(true) { lock(o1) //先锁o1 { lock(o2) //再锁o2 { count++; Console.WriteLine("这是Test1次数" + count); } } } } static void Test2() { while (true) { lock (o2) //先锁o2 { lock (o1) //再锁o1 { count++; Console.WriteLine("这是Test2次数" + count); } } } }
结果: