免费建造网站,微信公众号微网站开发,网站开发的流程是怎样的,提高seo关键词排名60年代#xff0c;在OS中能拥有资源和独立运行的基本单位是进程#xff0c;然而随着计算机技术的发展#xff0c;进程出现了很多弊端#xff0c;一是由于进程是资源拥有者#xff0c;创建、撤消与切换存在较大的时空开销#xff0c;因此需要引入轻型进程#xff1b;二是…60年代在OS中能拥有资源和独立运行的基本单位是进程然而随着计算机技术的发展进程出现了很多弊端一是由于进程是资源拥有者创建、撤消与切换存在较大的时空开销因此需要引入轻型进程二是由于对称多处理机SMP出现可以满足多个运行单位而多个进程并行开销过大。 因此在80年代出现了能独立运行的基本单位——线程Threads。 线程有时被称为轻量级进程(Lightweight ProcessLWP是程序执行流的最小单元。一个标准的线程由线程ID当前指令指针(PC寄存器集合和堆栈组成。另外线程是进程中的一个实体是被系统独立调度和分派的基本单位线程自己不拥有系统资源只拥有一点儿在运行中必不可少的资源但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件逻辑上可以运行在等待处理机运行状态是指线程占有处理机正在运行阻塞状态是指线程在等待一个事件如某个信号量逻辑上不可执行。每一个程序都至少有一个线程若程序只有一个线程那就是程序本身。 线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作称为多线程。 一、线程简义 1、进程与线程进程作为操作系统执行程序的基本单位拥有应用程序的资源进程包含线程进程的资源被线程共享线程不拥有资源。 2、前台线程和后台线程通过Thread类新建线程默认为前台线程。当所有前台线程关闭时所有的后台线程也会被直接终止不会抛出异常。 3、挂起Suspend和唤醒Resume由于线程的执行顺序和程序的执行情况不可预知所以使用挂起和唤醒容易发生死锁的情况在实际应用中应该尽量少用。 4、阻塞线程Join阻塞调用线程直到该线程终止。 5、终止线程Abort抛出 ThreadAbortException 异常让线程终止终止后的线程不可唤醒。Interrupt抛出 ThreadInterruptException 异常让线程终止通过捕获异常可以继续执行。 6、线程优先级AboveNormal BelowNormal Highest Lowest Normal默认为Normal。 二、线程的使用 线程函数通过委托传递可以不带参数也可以带参数只能有一个参数可以用一个类或结构体封装参数。 1 namespace Test2 {3 class Program4 {5 static void Main(string[] args)6 {7 Thread t1 new Thread(new ThreadStart(TestMethod));8 Thread t2 new Thread(new ParameterizedThreadStart(TestMethod));9 t1.IsBackground true;
10 t2.IsBackground true;
11 t1.Start();
12 t2.Start(hello);
13 Console.ReadKey();
14 }
15
16 public static void TestMethod()
17 {
18 Console.WriteLine(不带参数的线程函数);
19 }
20
21 public static void TestMethod(object data)
22 {
23 string datastr data as string;
24 Console.WriteLine(带参数的线程函数参数为{0}, datastr);
25 }
26 }
27 } 三、线程池 由于线程的创建和销毁需要耗费一定的开销过多的使用线程会造成内存资源的浪费出于对性能的考虑于是引入了线程池的概念。线程池维护一个请求队列线程池的代码从队列提取任务然后委派给线程池的一个线程执行线程执行完不会被立即销毁这样既可以在后台执行任务又可以减少线程创建和销毁所带来的开销。 线程池线程默认为后台线程IsBackground。 1 class Program2 {3 static void Main(string[] args)4 {5 //将工作项加入到线程池队列中这里可以传递一个线程参数6 ThreadPool.QueueUserWorkItem(TestMethod, Hello);7 Console.ReadKey();8 }9
10 public static void TestMethod(object data)
11 {
12 string datastr data as string;
13 Console.WriteLine(datastr);
14 }
15 } 四、Task类 使用ThreadPool的QueueUserWorkItem()方法发起一次异步的线程执行很简单但是该方法最大的问题是没有一个内建的机制让你知道操作什么时候完成有没有一个内建的机制在操作完成后获得一个返回值。为此可以使用System.Threading.Tasks中的Task类。 构造一个TaskTResult对象并为泛型TResult参数传递一个操作的返回类型。 1 class Program2 {3 static void Main(string[] args)4 {5 TaskInt32 t new TaskInt32(n Sum((Int32)n), 1000);6 t.Start();7 t.Wait();8 Console.WriteLine(t.Result);9 Console.ReadKey();
10 }
11
12 private static Int32 Sum(Int32 n)
13 {
14 Int32 sum 0;
15 for (; n 0; --n)
16 checked{ sum n;} //结果太大抛出异常
17 return sum;
18 }
19 } 一个任务完成时自动启动一个新任务。一个任务完成后它可以启动另一个任务下面重写了前面的代码不阻塞任何线程。 1 class Program2 {3 static void Main(string[] args)4 {5 TaskInt32 t new TaskInt32(n Sum((Int32)n), 1000);6 t.Start();7 //t.Wait();8 Task cwt t.ContinueWith(task Console.WriteLine(The result is {0},t.Result));9 Console.ReadKey();
10 }
11
12 private static Int32 Sum(Int32 n)
13 {
14 Int32 sum 0;
15 for (; n 0; --n)
16 checked{ sum n;} //结果溢出抛出异常
17 return sum;
18 }
19 } 五、委托异步执行 委托的异步调用BeginInvoke() 和 EndInvoke() 1 public delegate string MyDelegate(object data);2 class Program3 {4 static void Main(string[] args)5 {6 MyDelegate mydelegate new MyDelegate(TestMethod);7 IAsyncResult result mydelegate.BeginInvoke(Thread Param, TestCallback, Callback Param);8 9 //异步执行完成
10 string resultstr mydelegate.EndInvoke(result);
11 }
12
13 //线程函数
14 public static string TestMethod(object data)
15 {
16 string datastr data as string;
17 return datastr;
18 }
19
20 //异步回调函数
21 public static void TestCallback(IAsyncResult data)
22 {
23 Console.WriteLine(data.AsyncState);
24 }
25 } 六、线程同步 1原子操作Interlocked帮助保护免受计划程序切换上下文时某个线程正在更新可以由其他线程访问的变量或者在单独的处理器上同时执行两个线程就可能出现的错误。 此类的成员不会引发异常。 1 class Program2 {3 static int counter 1;4 5 static void Main(string[] args)6 {7 Thread t1 new Thread(new ThreadStart(F1));8 Thread t2 new Thread(new ThreadStart(F2));9
10 t1.Start();
11 t2.Start();
12
13 t1.Join();
14 t2.Join();
15
16 System.Console.ReadKey();
17 }
18
19 static void F1()
20 {
21 for (int i 0; i 5; i)
22 {
23 Interlocked.Increment(ref counter);
24 System.Console.WriteLine(Counter {0}, counter);
25 Thread.Sleep(10);
26 }
27 }
28
29 static void F2()
30 {
31 for (int i 0; i 5; i)
32 {
33 Interlocked.Decrement(ref counter);
34 System.Console.WriteLine(Counter-- {0}, counter);
35 Thread.Sleep(10);
36 }
37 }
38 } 2lock()语句避免锁定public类型否则实例将超出代码控制的范围定义private对象来锁定。而自定义类推荐用私有的只读静态对象比如private static readonly object obj new object();为什么要设置成只读的呢这时因为如果在lock代码段中改变obj的值其它线程就畅通无阻了因为互斥锁的对象变了object.ReferenceEquals必然返回false。Array 类型提供 SyncRoot。许多集合类型也提供 SyncRoot。 3Monitor实现线程同步 通过Monitor.Enter() 和 Monitor.Exit()实现排它锁的获取和释放获取之后独占资源不允许其他线程访问。 还有一个TryEnter方法请求不到资源时不会阻塞等待可以设置超时时间获取不到直接返回false。 1 public void MonitorSomeThing()2 {3 try4 {5 Monitor.Enter(obj);6 dosomething();7 }8 catch(Exception ex)9 {
10
11 }
12 finally
13 {
14 Monitor.Exit(obj);
15 }
16 } 4ReaderWriterLock 当对资源操作读多写少的时候为了提高资源的利用率让读操作锁为共享锁多个线程可以并发读取资源而写操作为独占锁只允许一个线程操作。 1 class SynchronizedCache 2 { 3 private ReaderWriterLockSlim cacheLock new ReaderWriterLockSlim(); 4 private Dictionaryint, string innerCache new Dictionaryint, string(); 5 6 public string Read(int key) 7 { 8 cacheLock.EnterReadLock(); 9 try 10 { 11 return innerCache[key]; 12 } 13 finally 14 { 15 cacheLock.ExitReaderLock(); 16 } 17 } 18 19 public void Add(int key, string value) 20 { 21 cacheLock.EnterWriteLock(); 22 try 23 { 24 innerCache.Add(key, value); 25 } 26 finally 27 { 28 cacheLock.ExitWriteLock(); 29 } 30 } 31 32 public bool AddWithTimeout(int key, string value, int timeout) 33 { 34 if (cacheLock.TryEnterWriteLock(timeout)) 35 { 36 try 37 { 38 innerCache.Add(key, value); 39 } 40 finally 41 { 42 cacheLock.ExitReaderLock(); 43 } 44 return true; 45 } 46 else 47 { 48 return false; 49 } 50 } 51 52 public AddOrUpdateStatus AddOrUpdate(int key, string value) 53 { 54 cacheLock.EnterUpgradeableReadLock(); 55 try 56 { 57 string result null; 58 if (innerCache.TryGetValue(key, out result)) 59 { 60 if (result value) 61 { 62 return AddOrUpdateStatus.Unchanged; 63 } 64 else 65 { 66 cacheLock.EnterWriteLock(); 67 try 68 { 69 innerCache[key] value; 70 } 71 finally 72 { 73 cacheLock.ExitWriteLock(); 74 } 75 return AddOrUpdateStatus.Updated; 76 } 77 } 78 else 79 { 80 cacheLock.EnterWriteLock(); 81 try 82 { 83 innerCache.Add(key, value); 84 } 85 finally 86 { 87 cacheLock.ExitWriteLock(); 88 } 89 return AddOrUpdateStatus.Added; 90 } 91 } 92 finally 93 { 94 cacheLock.ExitUpgradeableReadLock(); 95 } 96 } 97 98 public void Delete(int key) 99 {
100 cacheLock.EnterWriteLock();
101 try
102 {
103 innerCache.Remove(key);
104 }
105 finally
106 {
107 cacheLock.ExitWriteLock();
108 }
109 }
110
111 public enum AddOrUpdateStatus
112 {
113 Added,
114 Updated,
115 Unchanged
116 };
117 } 5事件Event类实现同步 事件类有两种状态终止状态和非终止状态终止状态时调用WaitOne可以请求成功通过Set将时间状态设置为终止状态。 1AutoResetEvent自动重置事件 2ManualResetEvent手动重置事件 AutoResetEvent和ManualResetEvent这两个类经常用到, 他们的用法很类似但也有区别。Set方法将信号置为发送状态Reset方法将信号置为不发送状态,WaitOne等待信号的发送。可以通过构造函数的参数值来决定其初始状态若为true则非阻塞状态为false为阻塞状态。如果某个线程调用WaitOne方法,则当信号处于发送状态时,该线程会得到信号, 继续向下执行。其区别就在调用后,AutoResetEvent.WaitOne()每次只允许一个线程进入,当某个线程得到信号后,AutoResetEvent会自动又将信号置为不发送状态,则其他调用WaitOne的线程只有继续等待.也就是说,AutoResetEvent一次只唤醒一个线程;而ManualResetEvent则可以唤醒多个线程,因为当某个线程调用了ManualResetEvent.Set()方法后,其他调用WaitOne的线程获得信号得以继续执行,而ManualResetEvent不会自动将信号置为不发送。也就是说,除非手工调用了ManualResetEvent.Reset()方法,则ManualResetEvent将一直保持有信号状态,ManualResetEvent也就可以同时唤醒多个线程继续执行。 6信号量Semaphore 信号量是由内核对象维护的int变量为0时线程阻塞大于0时解除阻塞当一个信号量上的等待线程解除阻塞后信号量计数1。 线程通过WaitOne将信号量减1通过Release将信号量加1使用很简单。 1 public Thread thrd;2 //创建一个可授权2个许可证的信号量且初始值为23 static Semaphore sem new Semaphore(2, 2);4 5 public mythread(string name)6 {7 thrd new Thread(this.run);8 thrd.Name name;9 thrd.Start();
10 }
11 void run()
12 {
13 Console.WriteLine(thrd.Name 正在等待一个许可证……);
14 //申请一个许可证
15 sem.WaitOne();
16 Console.WriteLine(thrd.Name 申请到许可证……);
17 for (int i 0; i 4 ; i)
18 {
19 Console.WriteLine(thrd.Name i);
20 Thread.Sleep(1000);
21 }
22 Console.WriteLine(thrd.Name 释放许可证……);
23 //释放
24 sem.Release();
25 }
26 }
27
28 class mysemaphore
29 {
30 public static void Main()
31 {
32 mythread mythrd1 new mythread(Thrd #1);
33 mythread mythrd2 new mythread(Thrd #2);
34 mythread mythrd3 new mythread(Thrd #3);
35 mythread mythrd4 new mythread(Thrd #4);
36 mythrd1.thrd.Join();
37 mythrd2.thrd.Join();
38 mythrd3.thrd.Join();
39 mythrd4.thrd.Join();
40 }
41 } 7互斥体Mutex 独占资源可以把Mutex看作一个出租车乘客看作线程。乘客首先等车然后上车最后下车。当一个乘客在车上时其他乘客就只有等他下车以后才可以上车。而线程与C# Mutex对象的关系也正是如此线程使用Mutex.WaitOne()方法等待C# Mutex对象被释放如果它等待的C# Mutex对象被释放了它就自动拥有这个对象直到它调用Mutex.ReleaseMutex()方法释放这个对象而在此期间其他想要获取这个C# Mutex对象的线程都只有等待。 1 class Test2 {3 /// summary4 /// 应用程序的主入口点。5 /// /summary6 [STAThread]7 static void Main(string[] args)8 {9 bool flag false;
10 System.Threading.Mutex mutex new System.Threading.Mutex(true, Test, out flag);
11 //第一个参数:true--给调用线程赋予互斥体的初始所属权
12 //第一个参数:互斥体的名称
13 //第三个参数:返回值,如果调用线程已被授予互斥体的初始所属权,则返回true
14 if (flag)
15 {
16 Console.Write(Running);
17 }
18 else
19 {
20 Console.Write(Another is Running);
21 System.Threading.Thread.Sleep(5000);//线程挂起5秒钟
22 Environment.Exit(1);//退出程序
23 }
24 Console.ReadLine();
25 }
26 } 8跨进程间的同步 通过设置同步对象的名称就可以实现系统级的同步不同应用程序通过同步对象的名称识别不同同步对象。 1 static void Main(string[] args)2 {3 string MutexName InterProcessSyncName;4 Mutex SyncNamed; //声明一个已命名的互斥对象5 try6 {7 SyncNamed Mutex.OpenExisting(MutexName); //如果此命名互斥对象已存在则请求打开8 }9 catch (WaitHandleCannotBeOpenedException)
10 {
11 SyncNamed new Mutex(false, MutexName); //如果初次运行没有已命名的互斥对象则创建一个
12 }
13 Task MulTesk new Task
14 (
15 () //多任务并行计算中的匿名方法用委托也可以
16 {
17 for (; ; ) //为了效果明显而设计
18 {
19 Console.WriteLine(当前进程等待获取互斥访问权......);
20 SyncNamed.WaitOne();
21 Console.WriteLine(获取互斥访问权访问资源完毕按回车释放互斥资料访问权.);
22 Console.ReadLine();
23 SyncNamed.ReleaseMutex();
24 Console.WriteLine(已释放互斥访问权。);
25 }
26 }
27 );
28 MulTesk.Start();
29 MulTesk.Wait();
30 } 9分布式的同步 可以使用redis任务队列或者redis相关特性 1 Parallel.For(0, 1000000, i 2 {3 Stopwatch sw1 new Stopwatch();4 sw1.Start();5 6 if (redisHelper.GetRedisOperation().Lock(key))7 {8 var tt int.Parse(redisHelper.GetRedisOperation().StringGet(calc));9
10 tt;
11
12 redisHelper.GetRedisOperation().StringSet(calc, tt.ToString());
13
14 redisHelper.GetRedisOperation().UnLock(key);
15 }
16 var v sw1.ElapsedMilliseconds;
17 if (v 10 * 1000)
18 {
19 Console.Write(f);
20 }
21 sw1.Stop();
22 }); 转载请标明本文来源http://www.cnblogs.com/yswenli/p/7421475.html 更多内容欢迎star作者的githubhttps://github.com/yswenli/如果发现本文有什么问题和任何建议也随时欢迎交流~ 转载于:https://www.cnblogs.com/yswenli/p/7421475.html