C#多线程技术总结(同步)

简介:

二、串行(同步):

1.lock、Monitor--注意锁定的对象必需是引用类型(string类型除外)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
         private  static  object  syncObject =  new  object ();
 
         private  static  void  TaskWork( object  i)
         {
             Console.WriteLine( "我是任务:{0}" ,i);
             lock  (syncObject)
             {
                 Thread.Sleep(1000);
                 Console.WriteLine( "我是任务:{0},线程ID:{1}" ,i,Thread.CurrentThread.ManagedThreadId);
             }
 
             try
             {
                 Monitor.Enter(syncObject);
                 Console.WriteLine( "我是任务:{0},线程ID:{1}" , i, Thread.CurrentThread.ManagedThreadId);
             }
             finally
             {
                 Monitor.Exit(syncObject);
             }
         }
 
//调用
Task.Factory.StartNew(TaskWork,1);
Task.Factory.StartNew(TaskWork, 2);

2.Interlocked

示例:

1
2
3
4
5
6
7
8
9
10
11
12
int  i=1;
Interlocked.Increment( ref  i);  //增量+1=2;
Console.WriteLine( "i当前的值:{0}" , i);
 
Interlocked.Decrement( ref  i);  //减量-1=0;
Console.WriteLine( "i当前的值:{0}" , i);
 
Interlocked.Exchange( ref  i, 2); //赋值=2;
Console.WriteLine( "i当前的值:{0}" ,i);
 
Interlocked.CompareExchange( ref  i, 10, 2); //比较交换值,当i=2时,则将i赋值为10;
Console.WriteLine( "i当前的值:{0}" , i);

3.Mutex--可以实现进程间的同步,甚至是两个远程进程间的同步

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var  t1 =  new  Task(() =>
{
     Console.WriteLine( "我是第一个任务!" );
     Mutex m =  new  Mutex( false "test" );
     m.WaitOne();
     Console.WriteLine( "第一个任务完成!" );
     m.ReleaseMutex();
});
 
var  t2 =  new  Task(() =>
{
     Console.WriteLine( "我是第二个任务!" );
     Mutex m =  new  Mutex( false "test" );
     m.WaitOne();
     Console.WriteLine( "第二个任务完成!" );
     m.ReleaseMutex();
});
 
t1.Start();
t2.Start();

 4.ReaderWriterLock 、ReaderWriterLockSlim--如果在某一时刻资源并没有获取写的独占权,那么可以获得多个读的访问权,单个写入的独占权,如果某一时刻已经获取了写入的独占权,那么其它读取的访问权必须进行等待. 

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
     static  ReaderWriterLock rwLock =  new  ReaderWriterLock();
 
     static  void  Read( object  state)
     {
         Console.WriteLine( "我是读线程,线程ID是:{0}" ,Thread.CurrentThread.ManagedThreadId);
         rwLock.AcquireReaderLock(Timeout.Infinite); //无限期等待,需要显式调用ReleaseReaderLock释放锁
         var  readList = state  as  IEnumerable< int >;
         foreach  ( int  item  in  readList)
         {
             Console.WriteLine( "读取当前的值为:{0}" , item);
             Thread.Sleep(500);
         }
         Console.WriteLine( "读完成,线程ID是:{0}" , Thread.CurrentThread.ManagedThreadId);
         rwLock.ReleaseReaderLock();
         
     }
 
 
     static  void  Write( object  state)
     {
         Console.WriteLine( "我是写线程,线程ID是:{0}" , Thread.CurrentThread.ManagedThreadId);
         rwLock.AcquireWriterLock(Timeout.Infinite);  //无限期等待,需要显式调用ReleaseWriterLock释放锁
         var  writeList = state  as  List< int >;
         int  lastCount=writeList.Count();
         for  ( int  i = lastCount; i <= 10+lastCount; i++)
         {
             writeList.Add(i);
             Console.WriteLine( "写入当前值:{0}" ,i);
             Thread.Sleep(500);
         }
         Console.WriteLine( "写完成,线程ID是:{0}" , Thread.CurrentThread.ManagedThreadId);
         rwLock.ReleaseWriterLock();
     }
 
//调用:
         var  rwList =  new  List< int >();
 
         var  t1 =  new  Thread(Write);
         var  t2 =  new  Thread(Read);
         var  t3 =  new  Thread(Write);
         var  t4 =  new  Thread(Read);
         
         t1.Start(rwList);
         t2.Start(rwList);
         t3.Start(rwList);
         t4.Start(rwList);

 

5.SynchronizationAttribute--确保某个类的实例在同一时刻只能被一个线程访问,类的定义要求:A.类上必需标记SynchronizationAttribute特性,B.类必需继承自System.ContextBoundObject对象

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
     [Synchronization(SynchronizationAttribute.REQUIRED, true )]
     public  class  Account : System.ContextBoundObject
     {
         private  static  int  _balance;
         public  int  Blance
         {
             get
             {
                 return  _balance;
             }
         }
 
         public  Account()
         {
             _balance = 1000;
         }
 
         public  void  WithDraw( string  name, object  money)
         {
             if  (( int )money <= _balance)
             {
                 Thread.Sleep(2000);
                 _balance = _balance - ( int )money;
                 Console.WriteLine( "{0} 取钱成功!余额={1}" , name, _balance);
             }
             else
             {
                 Console.WriteLine( "{0} 取钱失败!余额不足!" , name);
             }
         }
     }
 
//调用:
             var  account =  new  Account();
             Parallel.Invoke(() =>
             {
                 account.WithDraw( "张三" ,600);
 
             }, () =>
             {
                 account.WithDraw( "李四" ,600);
             });

6.MethodImplAttribute--使整个方法上锁,直到方法返回,才释放锁

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
     public  class  Account
     {
         private  static  int  _balance;
         public  int  Blance
         {
             get
             {
                 return  _balance;
             }
         }
 
         public  Account()
         {
             _balance = 1000;
         }
 
         [MethodImpl(MethodImplOptions.Synchronized)]
         public  void  WithDraw( string  name, object  money)
         {
             if  (( int )money <= _balance)
             {
                 Thread.Sleep(2000);
                 _balance = _balance - ( int )money;
                 Console.WriteLine( "{0} 取钱成功!余额={1}" , name, _balance);
             }
             else
             {
                 Console.WriteLine( "{0} 取钱失败!余额不足!" , name);
             }
         }
     }
 
//调用
             var  account =  new  Account();
             Parallel.Invoke(() =>
             {
                 account.WithDraw( "张三" ,600);
 
             }, () =>
             {
                 account.WithDraw( "李四" ,600);
             });

7.AutoResetEvent、ManualResetEvent、ManualResetEventSlim--调用WaitOne、WaitAny或WaitAll来使线程等待事件,调用Set方法发送信号,事件将变为终止状态,等待的线程被唤醒

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
AutoResetEvent arEvent =  new  AutoResetEvent( false ); //默认为无信号,处于非终止状态
Task.Factory.StartNew((o) => {
     for  ( int  i = 1; i <= 10; i++)
     {
         Console.WriteLine( "循环第{0}次" ,i);
     }
     arEvent.Set(); //发送信号,处于终止状态
},arEvent);
 
 
arEvent.WaitOne(); //等待信号,收到信号后则继续下面的执行
 
Console.WriteLine( "我是主线程,我继续执行!" );
Console.Read();

 8.Sempaphore、SemaphoreSlim(不可跨进程)--信号量,可实现线程、进程间同步

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
     public  class  WashRoom
     {
         private  readonly  Semaphore sem;
 
         public  WashRoom( int  maxUseableCount)
         {
             sem =  new  Semaphore(maxUseableCount, maxUseableCount,  "WC" );
         }
 
         public  void  Use( int  i)
         {
             Task.Factory.StartNew(() =>
                 {
                     Console.WriteLine( "第{0}个人等待进入" , i);
                     // WaitOne:如果还有“空位”,则占位,如果没有空位,则等待;
                     sem.WaitOne();
                     Console.WriteLine( "第{0}个人成功进入,使用中" , i);
                     // 模拟线程执行了一些操作
                     Thread.Sleep(100);
                     Console.WriteLine( "第{0}个人用完,离开了" , i);
                     // Release:释放一个“空位”
                     sem.Release();
                 });
         }
     }
 
//调用:
             var  wc =  new  WashRoom(5);
             for  ( int  i = 1; i <= 7; i++)
             {
                 wc.Use(i);
             }

9.Barrier--屏障,使多个任务能够采用并行方式依据某种算法在多个阶段中协同工作,即:将一个阶段的事情分成多个线程来异步执行,执行完毕后再同时进入下一个阶段

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int  taskSize = 5;
Barrier barrier =  new  Barrier(taskSize, (b) =>
{
     Console.WriteLine( string .Format( "{0}当前阶段编号:{1}{0}" "-" .PadRight(15,  '-' ), b.CurrentPhaseNumber));
});
 
var  tasks =  new  Task[taskSize];
 
for  ( int  i = 0; i < taskSize; i++)
{
     tasks[i] = Task.Factory.StartNew((n) =>
     {
         Console.WriteLine( "Task : #{0}   ---->  处理了第一部份数据。" , n);
         barrier.SignalAndWait();
 
         Console.WriteLine( "Task : #{0}   ---->  处理了第二部份数据。" , n);
         barrier.SignalAndWait();
 
         Console.WriteLine( "Task : #{0}   ---->  处理了第三部份数据。" , n);
         barrier.SignalAndWait();
 
     }, i);
}
 
Task.WaitAll(tasks);

10.SpinLock--自旋锁,仅限锁定的时间较短

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
             SpinLock sLock =  new  SpinLock();
             int  num = 0;
             Action action = () =>
             {
                 bool  lockTaken =  false ;
                 for  ( int  i = 0; i < 10; i++)
                 {
                     lockTaken =  false ;
                     try
                     {
                         sLock.Enter( ref  lockTaken);
                         Console.WriteLine( "{0}+1={1} ---线程ID:[{2}]" , num, ++num,Thread.CurrentThread.ManagedThreadId);
                         Thread.Sleep( new  Random().Next(9));
                     }
                     finally
                     {
                         //真正获取之后,才释放
                         if  (lockTaken) sLock.Exit();
                     }
                 }
             };
 
//多线程调用:
             Parallel.Invoke(action, action, action);
             Console.WriteLine( "合计:{0}" , num);

11.SpinWait--自旋等待,轻量级

1
2
3
4
5
6
7
8
Thread.Sleep(1000); //线程等待1S;
Console.WriteLine(DateTime.Now.ToString( "yyyy-MM-dd HH:mm:ss.fff" ));
 
SpinWait.SpinUntil(() =>  false , 1000); //自旋等待1S
Console.WriteLine(DateTime.Now.ToString( "yyyy-MM-dd HH:mm:ss.fff" ));
 
Thread.SpinWait(100000); //指定CPU的循环次数,时间间隔处决于处理器的运行速度,一般不建议使用
Console.WriteLine(DateTime.Now.ToString( "yyyy-MM-dd HH:mm:ss.fff" ));

12.CountdownEvent--与Sempaphore功能类似,但CountdownEvent支持动态调整信号计数

 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
         static  void  TimeLimitShopping( int  custCount, int  times,CountdownEvent countdown)
         {
             var  customers = Enumerable.Range(1, custCount);
             foreach  ( var  customer  in  customers)
             {
                 int  currentCustomer = customer;
                Task.Factory.StartNew(()=>
                 {
                     SpinWait.SpinUntil(() =>  false , 1000);
                     Console.WriteLine( "第{0}波客户购买情况:Customer-{1}-已购买." , times, currentCustomer);
                     countdown.Signal();
                 });
                 //countdown.AddCount();
             }
         }
 
 
//调用:
var  countdown =  new  CountdownEvent(5);
                 TimeLimitShopping(5, 1, countdown);
                 countdown.Wait();
 
 
                 countdown.Reset(10);
                 TimeLimitShopping(10, 2, countdown);
                 countdown.Wait();
 
                 countdown.Reset(20);
                 TimeLimitShopping(20, 3, countdown);
                 countdown.Wait();

 最后分享在System.Collections.Concurrent命名空间下的几个并发集合类:

ConcurrentBag<T>:表示线程安全的无序集合;

ConcurrentDictionary<T>:表示线程安全的多个键值对集合;

ConcurrentQueue<T>:表示线程安全的先进先出集合;

ConcurrentStack<T>:表示线程安全的后进先出集合;

线程的几个状态(以下图片来源于这篇文章:http://www.cnblogs.com/edisonchou/p/4848131.html):

参考以下相关文章:

归纳一下:C#线程同步的几种方法

C#编程总结(三)线程同步

 

本文转自 梦在旅途 博客园博客,原文链接: http://www.cnblogs.com/zuowj/p/4910512.html ,如需转载请自行联系原作者

相关文章
|
1月前
|
Java 云计算
Java多线程编程中的同步与互斥机制探析
在当今软件开发领域,多线程编程是一项至关重要的技能。本文将深入探讨Java中的同步与互斥机制,分析其在多线程环境下的应用及实现原理,帮助读者更好地理解并运用这一关键技术。
22 4
|
1月前
|
Java 调度 C#
C#学习系列相关之多线程(一)----常用多线程方法总结
C#学习系列相关之多线程(一)----常用多线程方法总结
|
1月前
|
安全 编译器 C#
C#学习相关系列之多线程---lock线程锁的用法
C#学习相关系列之多线程---lock线程锁的用法
|
1月前
|
C#
C#学习相关系列之多线程---ConfigureAwait的用法
C#学习相关系列之多线程---ConfigureAwait的用法
|
1月前
|
C#
C#学习相关系列之多线程---TaskCompletionSource用法(八)
C#学习相关系列之多线程---TaskCompletionSource用法(八)
|
27天前
|
安全 Python
Python中的并发编程:多线程与多进程技术探究
本文将深入探讨Python中的并发编程技术,重点介绍多线程和多进程两种并发处理方式的原理、应用场景及优缺点,并结合实例分析如何在Python中实现并发编程,以提高程序的性能和效率。
|
21天前
|
NoSQL 数据处理 调度
【Redis深度专题】「踩坑技术提升」探索Redis 6.0为何必须启用多线程以提升性能与效率
【Redis深度专题】「踩坑技术提升」探索Redis 6.0为何必须启用多线程以提升性能与效率
45 0
|
9天前
|
数据采集 C# 数据安全/隐私保护
掌握 C# 爬虫技术:使用 HttpClient 获取今日头条内容
本文介绍了如何使用C#的HttpClient与爬虫代理IP技术抓取今日头条内容,以实现高效的数据采集。通过结合亿牛云爬虫代理,可以绕过IP限制,增强匿名性。文中提供了一个代码示例,展示如何设置代理服务器信息、请求头,并用正则表达式提取热点新闻标题。利用多线程技术,能提升爬虫采集效率,为市场分析等应用提供支持。
掌握 C# 爬虫技术:使用 HttpClient 获取今日头条内容
|
26天前
|
存储 编解码 算法
【ffmpeg音视频同步】解决ffmpeg音视频中多线程之间的数据同步问题
【ffmpeg音视频同步】解决ffmpeg音视频中多线程之间的数据同步问题
38 2
|
1月前
|
缓存 编译器 程序员
C/C++编译器并行优化技术:并行优化针对多核处理器和多线程环境进行优化,以提高程序的并行度
C/C++编译器并行优化技术:并行优化针对多核处理器和多线程环境进行优化,以提高程序的并行度
60 0

相关实验场景

更多