博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#多线程技术总结(同步)
阅读量:6248 次
发布时间:2019-06-22

本文共 8462 字,大约阅读时间需要 28 分钟。

二、串行(同步):

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):

参考以下相关文章:

 

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

你可能感兴趣的文章
c/c++ 获取文件夹或目录下的文件
查看>>
bzoj3316: JC loves Mkk(单调队列+分数规划)
查看>>
P4046 [JSOI2010]快递服务
查看>>
8分钟学会使用AutoMapper
查看>>
使用weka训练一个分类器
查看>>
C#根据WSDL文件生成WebService服务端代码
查看>>
[FJOI2018]领导集团问题
查看>>
thinkphp用ajax遇到的坑——ajax请求没有反应
查看>>
Microsoft Visual Studio 中出现 Windows has triggered a breakpoint in xxx.exe的一个解决方案
查看>>
非常直白的 js 闭包概念.<转载>
查看>>
shared_ptr模版推导的问题
查看>>
mac下用ruby安装sass && webstorm下给scss文件添加watch
查看>>
前端Demo常用库文件链接
查看>>
react create-react-app 跨域
查看>>
python html parse
查看>>
本机连接调试Erlang结点与rebar3编译
查看>>
web基础html元素制作web
查看>>
Codeforces 96C - Hockey
查看>>
生成树协议
查看>>
Web应用三种部署方式的优缺点
查看>>