当前位置:网站首页>C#(四十二)之线程同步、互锁
C#(四十二)之线程同步、互锁
2022-07-20 23:23:00 【camellias_】
无关线程:线程之间没有任何联系,独立运行,互不干扰
相关线程:线程之间有联系,两个线程之间资源共享
临界线程:多个线程共享资源
临界区:访问临界资源代码
同步:两个线程协同工作才能完成同一项任务
相关线程实例:
public static char buffer;
public static string str;
static void Main(string[] args)
{
// 开写线程
Thread th = new Thread(write);
th.Start();
// 开度线程
Thread re = new Thread(delegate() {
for (int i = 0; i < str.Length; i++)
{
char ch = buffer;
Console.Write(ch); // 醒木非根,半风走一,谈疏君莫,是一说人人人人人人人人人人人人人
Thread.Sleep(50);
}
});
re.Start();
Console.ReadLine();
}
/// <summary>
/// 写入
/// </summary>
public static void write()
{
str = "醒木本非同根生,半生风雨走一程,谈笑疏狂君莫问,却是一位说书人";
for (int i = 0; i < str.Length; i++)
{
buffer = str[i];
Thread.Sleep(30);
}
}
打印结果:
醒木非根,半风走一,谈疏君莫,是一说人人人人人人人人人人人人人
造成这种情况的原因是:读写线程时间不相同。
Interlocked(互锁):
使用线程锁Interlocked来解决这个问题
Interlocked的一些属性
Interlocked.Increment(ref value) 数值加一(原子性操作)
Interlocked.Decrement(ref value) 数值减一(原子性操作)
Interlocked.Exchange(ref value1, value2) 交换:把值2赋给值1;返回新值
Interlocked.CompareExchange(ref value1, value2, value3) 实现比较和交换两种功能:值1和值3比较,如果相同,把值2给值1,不相同则不作任何操作;返回原值(多用于判断条件)
Interlocked.Read读取计数器的值
Interlocked.Add使计数器增加指定的值
使用Interlocked改造完成之后的代码:
// 开写线程
Thread th = new Thread(write);
th.Start();
// 开度线程
Thread re = new Thread(delegate() {
for (int i = 0; i < str.Length; i++)
{
while (Interlocked.Read(ref num) == 0)
{
Thread.Sleep(10);
}
char ch = buffer;
Console.Write(ch);
//Thread.Sleep(50);
// 使值减少1
Interlocked.Decrement(ref num);
}
});
re.Start();
Console.ReadLine();
}
/// <summary>
/// 写入
/// </summary>
public static void write()
{
str = "醒木本非同根生,半生风雨走一程,谈笑疏狂君莫问,却是一位说书人";
for (int i = 0; i < str.Length; i++)
{
while (Interlocked.Read(ref num) == 1)
{
Thread.Sleep(10);
}
buffer = str[i];
//Thread.Sleep(30);
// 使值增加1
Interlocked.Increment(ref num);
}
}
Monitor(管程):
配合try-catch-finally(需要退出exit)或者Lock使用
锁定的对象应该声明为private static object obj = new object();尽量别用公共变量和字符串、this、值类型。
属性和方法:
Enter(Object) 在指定对象上获取排他锁。
Exit(Object) 释放指定对象上的排他锁。
IsEntered 确定当前线程是否保留指定对象锁。
Pulse 通知等待队列中的线程锁定对象状态的更改。
PulseAll 通知所有的等待线程对象状态的更改。
TryEnter(Object) 试图获取指定对象的排他锁。
TryEnter(Object, Boolean) 尝试获取指定对象上的排他锁,并自动设置一个值,指示是否得到了该锁。
Wait(Object) 释放对象上的锁并阻止当前线程,直到它重新获取该锁。
public static char buffer;
public static string str;
/// <summary>
/// 此变量为InterLocked使用
/// </summary>
public static long num;
/// <summary>
/// 此变量为Monitor 使用
/// </summary>
public static object obj = new object();
static void Main(string[] args)
{
// 开写线程
Thread th = new Thread(write);
th.Start();
// 开度线程
Thread re = new Thread(delegate() {
try
{
for (int i = 0; i < str.Length; i++)
{
/*while (Interlocked.Read(ref num) == 0)
{
Thread.Sleep(10);
}//*/
// 程序进入临界区,上锁
Monitor.Enter(obj);
char ch = buffer;
Console.Write(ch);
// 通知等待队列中的线程锁定对象状态的更改
Monitor.Pulse(obj);
// 释放对象上的锁并阻止当前线程,直到它重新获取该锁
Monitor.Wait(obj);
/*//Thread.Sleep(50);
// 使值减少1
Interlocked.Decrement(ref num);//*/
}
}
catch (Exception)
{
throw;
}
finally
{
Monitor.Exit(obj);
}
});
re.Start();
Console.ReadLine();
}
/// <summary>
/// 写入
/// </summary>
public static void write()
{
try
{
str = "醒木本非同根生,半生风雨走一程,谈笑疏狂君莫问,却是一位说书人";
for (int i = 0; i < str.Length; i++)
{
/*while (Interlocked.Read(ref num) == 1)
{
Thread.Sleep(10);
}//*/
// 程序进入临界区,上锁
Monitor.Enter(obj);
buffer = str[i];
// 通知等待队列中的线程锁定对象状态的更改
Monitor.Pulse(obj);
// 释放对象上的锁并阻止当前线程,直到它重新获取该锁
Monitor.Wait(obj);
/*//Thread.Sleep(30);
// 使值增加1
Interlocked.Increment(ref num);//*/
}
}
catch (Exception)
{
throw;
}
finally {
Monitor.Exit(obj);
}
}
Lock:上锁
Monitor和Lock的区别
1.Lock是Monitor的语法糖。
2.Lock只能针对引用类型加锁。
3.Monitor能够对值类型进行加锁,实质上是Monitor.Enter(object)时对值类型装箱。
4.Monitor还有其他的一些功能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1FF05HWw-1658305676246)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b7444c97a2c0455693d468fbdc8c09b8~tplv-k3u1fbpfcp-zoom-1.image “1559178866415958.png”)]
使用lock代替try之后:程序变得简洁了一些:仅限于Monitor
static void Main(string[] args)
{
// 开写线程
Thread th = new Thread(write);
th.Start();
// 开度线程
Thread re = new Thread(delegate() {
for (int i = 0; i < str.Length; i++)
{
lock (obj)
{
/*while (Interlocked.Read(ref num) == 0)
{
Thread.Sleep(10);
}//*/
char ch = buffer;
Console.Write(ch);
// 通知等待队列中的线程锁定对象状态的更改
Monitor.Pulse(obj);
// 释放对象上的锁并阻止当前线程,直到它重新获取该锁
Monitor.Wait(obj);
/*//Thread.Sleep(50);
// 使值减少1
Interlocked.Decrement(ref num);//*/
}
}
});
re.Start();
Console.ReadLine();
}
/// <summary>
/// 写入
/// </summary>
public static void write()
{
str = "醒木本非同根生,半生风雨走一程,谈笑疏狂君莫问,却是一位说书人";
for (int i = 0; i < str.Length; i++)
{
lock(obj)
{
/*while (Interlocked.Read(ref num) == 1)
{
Thread.Sleep(10);
}//*/
buffer = str[i];
// 通知等待队列中的线程锁定对象状态的更改
Monitor.Pulse(obj);
// 释放对象上的锁并阻止当前线程,直到它重新获取该锁
Monitor.Wait(obj);
/*//Thread.Sleep(30);
// 使值增加1
Interlocked.Increment(ref num);//*/
}
}
}
以上方法对资源消耗比较大,合理使用
有好的建议,请在下方输入你的评论。
欢迎访问个人博客
https://guanchao.site
欢迎访问小程序:
边栏推荐
- JS operators and expressions \ flow structure of functions and programs
- Analysis of tars source code 21
- Huawei wireless devices are configured with rapid roaming between APs of different service VLANs
- The remote control software should also have plan B alternatives
- 12、用户微服务
- (c语言)柔性数组
- Ultra simple three tube inductive brushless three-phase motor drive board
- Why is report development still a headache after using famous tools
- Power Bi ---- slicer to make the report more beautiful
- [email protected]交互
猜你喜欢
随机推荐
Codeforces Round #809 (Div. 2)
JS--循环--猜数字(生成随机数存在小数Math.random)
【RViz2】导入urdf模型时报错:Could not load resource xxx,Unable to open file xxx,Error retrieving file xxx
(c语言)柔性数组
OpenCV学习——ArUco模块
The difference between memory overflow and memory leak
JS-数据类型-和转换
YOLOv5改进之二:添加CBAM注意力机制
mysql 常用操作和基础查询
Data analysis demo
同城多数据中心部署 TiDB
【机器学习】如何在训练过程中挑选比较好的模型保存(pytorch)
[pictures and texts] this article explains the JVM architecture, class file structure and bytecode structure!!
已解决Module not found: Error: Can‘t resolve ‘core-js/fn/reflect‘ in
The remote control software should also have plan B alternatives
cv demo
Replication of complex linked list
Is there a completely independent localization database technology
静态通讯录的实现
对等网主机的通信过程以及原理,很简单