C#多线程学习笔记(四) --Lock and Monitor之二

简介: a.Monitor方法(MSDN摘录)Enter, TryEnter 获取对象锁,此操作同样会标记临界区的开头。其他任务线程都不能进入临界区,除非它使用其他锁定对象执行临界区的指令。
a.Monitor方法(MSDN摘录)

Enter, TryEnter 获取对象锁,此操作同样会标记临界区的开头。其他任务线程都不能进入临界区,除非它使用其他锁定对象执行临界区的指令。
Wait 释放对象上的锁以便允许其他线程锁定和访问该对象。在其他线程访问对象时,调用线程将等待。脉冲信号用于通知待待线程有关对象状态的更改。

Pulse(信号),PulseAll

向一个或多个等待线程发送信号。该信号通知等待线程锁定对象的状态已更改,并且锁的所有者准备释放该锁。等待线程被放置在对象的就绪队列中以便它可以最后接收对象锁。一旦线程摇篮有了锁,它就可以检查对象的新状态以查看是否达到所需状态。
Exit 释放对象上的锁。此操作还标记受锁定对象保护的临界区的结尾。

b.Sample
img_a6339ee3e57d1d52bc7d02b338e15a60.gif using  System;
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
using  System.Collections.Generic;
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
using  System.Text;
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
using  System.Threading;
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
img_a6339ee3e57d1d52bc7d02b338e15a60.gif
namespace  ThreadLockAndMonitor
img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif {
img_33d02437d135341f0800e3d415312ae8.gif    
public class Cell
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif        
int cellContents;// Cell对象里边的内容
img_33d02437d135341f0800e3d415312ae8.gif
        bool FAllowReader = false;// 状态标志,为true时可以读取,为false则正在写入
img_33d02437d135341f0800e3d415312ae8.gif
        public int ReadfromCell()
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            
lock (this)// Lock关键字保证了该块只有一个线程可以进来
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
            img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                
if (!FAllowReader)//如果现在不可读取
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
                img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                    
try
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                        
//等待WriteToCell方法中调用Monitor.Pulse()方法
img_33d02437d135341f0800e3d415312ae8.gif
                        Monitor.Wait(this);
img_105a1e124122b2abcee4ea8e9f5108f3.gif                    }

img_33d02437d135341f0800e3d415312ae8.gif                    
catch (SynchronizationLockException e)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                        Console.WriteLine(e.Message);
img_105a1e124122b2abcee4ea8e9f5108f3.gif                    }

img_33d02437d135341f0800e3d415312ae8.gif                    
catch (ThreadInterruptedException e)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                        Console.WriteLine(e);
img_105a1e124122b2abcee4ea8e9f5108f3.gif                    }

img_105a1e124122b2abcee4ea8e9f5108f3.gif                }

img_33d02437d135341f0800e3d415312ae8.gif                Console.WriteLine(
"Consume:{0}", cellContents);
img_33d02437d135341f0800e3d415312ae8.gif                FAllowReader 
= false;//重置FAllowReader标志,表示消费行为已经完成
img_33d02437d135341f0800e3d415312ae8.gif
                Monitor.Pulse(this);//通知WriteToCell()方法(该方法在另外一个线程中执行,等待中)
img_105a1e124122b2abcee4ea8e9f5108f3.gif
            }

img_33d02437d135341f0800e3d415312ae8.gif            
return cellContents;
img_105a1e124122b2abcee4ea8e9f5108f3.gif        }

img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif        
public void WriteToCell(int _n)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            
lock(this)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                
if (FAllowReader)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                    
try
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                        Monitor.Wait(
this);
img_105a1e124122b2abcee4ea8e9f5108f3.gif                    }

img_33d02437d135341f0800e3d415312ae8.gif                    
catch(SynchronizationLockException e)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                        
//当同步方法(指Monitor类除Enter之外的方法)在非同步的代码区被调用
img_33d02437d135341f0800e3d415312ae8.gif
                        Console.WriteLine(e);
img_105a1e124122b2abcee4ea8e9f5108f3.gif                    }

img_33d02437d135341f0800e3d415312ae8.gif                    
catch(ThreadInterruptedException e)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                        
//当线程在等待状态的时候中止
img_33d02437d135341f0800e3d415312ae8.gif
                        Console.WriteLine(e);
img_105a1e124122b2abcee4ea8e9f5108f3.gif                    }

img_105a1e124122b2abcee4ea8e9f5108f3.gif                }

img_33d02437d135341f0800e3d415312ae8.gif                cellContents 
= _n;
img_33d02437d135341f0800e3d415312ae8.gif                Console.WriteLine(
"Procduce:{0}", cellContents);
img_33d02437d135341f0800e3d415312ae8.gif                FAllowReader 
= true;
img_33d02437d135341f0800e3d415312ae8.gif                Monitor.Pulse(
this);//通知另外一个线程中正在等待的ReadFromCell()方法
img_105a1e124122b2abcee4ea8e9f5108f3.gif
            }

img_105a1e124122b2abcee4ea8e9f5108f3.gif        }

img_105a1e124122b2abcee4ea8e9f5108f3.gif  }

img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif    
public class CellProd
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif        Cell cell;
// 被操作的Cell对象
img_33d02437d135341f0800e3d415312ae8.gif
        int quantity = 1;//生产者生产次数,初始化为1
img_33d02437d135341f0800e3d415312ae8.gif
        public CellProd(Cell _box, int _request)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            cell 
= _box;
img_33d02437d135341f0800e3d415312ae8.gif            quantity 
= _request;
img_105a1e124122b2abcee4ea8e9f5108f3.gif        }

img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif        
public void ThreadRun()
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            
for(int i = 1; i<=quantity; i++)
img_33d02437d135341f0800e3d415312ae8.gif                cell.WriteToCell(i);
//生产者向操作对象写入信息
img_105a1e124122b2abcee4ea8e9f5108f3.gif
        }

img_105a1e124122b2abcee4ea8e9f5108f3.gif    }

img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif    
public class CellCons
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif        Cell cell;
img_33d02437d135341f0800e3d415312ae8.gif        
int quantity = 1;
img_33d02437d135341f0800e3d415312ae8.gif        
public CellCons(Cell _box, int _request)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            cell 
= _box;
img_33d02437d135341f0800e3d415312ae8.gif            quantity 
= _request;
img_105a1e124122b2abcee4ea8e9f5108f3.gif        }

img_33d02437d135341f0800e3d415312ae8.gif        
public void ThreadRun()
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            
int valReturned;
img_33d02437d135341f0800e3d415312ae8.gif            
for (int i = 1; i<=quantity; i++)
img_33d02437d135341f0800e3d415312ae8.gif                valReturned 
= cell.ReadfromCell();//消费者从操作对象中读取信息
img_105a1e124122b2abcee4ea8e9f5108f3.gif
        }

img_33d02437d135341f0800e3d415312ae8.gif
img_105a1e124122b2abcee4ea8e9f5108f3.gif    }

img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif 
img_33d02437d135341f0800e3d415312ae8.gif    
class Program
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif        
static void Main(string[] args)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif            
int result = 0;//一个标志位,如果是0表示程序没有出错,如果是1表明有错误发生
img_33d02437d135341f0800e3d415312ae8.gif
            Cell cell = new Cell();
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif            
//下面使用cell初始化CellProd和CellCons两个类,生产和消费次数均为20次
img_33d02437d135341f0800e3d415312ae8.gif
            CellProd prod = new CellProd(cell, 20);
img_33d02437d135341f0800e3d415312ae8.gif            CellCons cons 
= new CellCons(cell, 20);
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif            Thread producer 
= new Thread(new ThreadStart(prod.ThreadRun));
img_33d02437d135341f0800e3d415312ae8.gif            Thread consumer 
= new Thread(new ThreadStart(cons.ThreadRun));
img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif            
//生产者线程和消费者线程都已经被创建,但是没有开始执行
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
            tryimg_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                producer.Start();
img_33d02437d135341f0800e3d415312ae8.gif                consumer.Start();
img_33d02437d135341f0800e3d415312ae8.gif                
img_33d02437d135341f0800e3d415312ae8.gif                producer.Join();
img_33d02437d135341f0800e3d415312ae8.gif                consumer.Join();
img_33d02437d135341f0800e3d415312ae8.gif                Console.ReadLine();
img_105a1e124122b2abcee4ea8e9f5108f3.gif            }

img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
catch(ThreadStateException e)img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                Console.WriteLine(e);
img_33d02437d135341f0800e3d415312ae8.gif                result 
= 1;
img_105a1e124122b2abcee4ea8e9f5108f3.gif            }

img_33d02437d135341f0800e3d415312ae8.gif            
catch(ThreadInterruptedException e)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif            
img_a76e9bb6ed00cf1c9c9f4ee2f04b558b.gif{
img_33d02437d135341f0800e3d415312ae8.gif                
//当线程在等待状态的时候中止
img_33d02437d135341f0800e3d415312ae8.gif
                Console.WriteLine(e);
img_33d02437d135341f0800e3d415312ae8.gif                result 
= 1;
img_105a1e124122b2abcee4ea8e9f5108f3.gif            }

img_33d02437d135341f0800e3d415312ae8.gif
img_33d02437d135341f0800e3d415312ae8.gif            
//尽管Main()函数没有返回值,但下面这条语句可以向父进程返回执行结果
img_33d02437d135341f0800e3d415312ae8.gif
            Environment.ExitCode = result;
img_105a1e124122b2abcee4ea8e9f5108f3.gif        }

img_105a1e124122b2abcee4ea8e9f5108f3.gif    }

img_05dd8d549cff04457a6366b0a7c9352a.gif}

img_a6339ee3e57d1d52bc7d02b338e15a60.gif

 可以看到,在上面的例程中,同步是通过等待Monitor.Pulse()来完成的。首先生产者生产了一个值,而同一时刻消费者处于等待状态,直到收到生产者的“脉冲(Pulse)”通知它生产已经完成,此后消费者进入消费状态,而生产者开始等待消费者完成操作后将调用Monitor.Pulese()发出的“脉冲”。它的执行结果很简单:
Produce: 1
Consume: 1
Produce: 2
Consume: 2
Produce: 3
Consume: 3
...
...
Produce: 20
Consume: 20
事实上,这个简单的例子已经帮助我们解决了多线程应用程序中可能出现的大问题,只要领悟了解决线程间冲突的基本方法,很容易把它应用到比较复杂的程序中去。

目录
相关文章
|
22天前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
Java多线程同步大揭秘:synchronized与Lock的终极对决!
54 5
|
22天前
|
安全 Java 开发者
Java多线程同步:synchronized与Lock的“爱恨情仇”!
Java多线程同步:synchronized与Lock的“爱恨情仇”!
78 5
|
22天前
|
Java 开发者
揭秘!为什么大神都爱用Lock接口处理线程同步?
揭秘!为什么大神都爱用Lock接口处理线程同步?
37 5
|
22天前
|
Java
在Java多线程领域,精通Lock接口是成为高手的关键。
在Java多线程领域,精通Lock接口是成为高手的关键。相较于传统的`synchronized`,Lock接口自Java 5.0起提供了更灵活的线程同步机制,包括可中断等待、超时等待及公平锁选择等高级功能。本文通过实战演练介绍Lock接口的核心实现——ReentrantLock,并演示如何使用Condition进行精确线程控制,帮助你掌握这一武林秘籍,成为Java多线程领域的盟主。示例代码展示了ReentrantLock的基本用法及Condition在生产者-消费者模式中的应用,助你提升程序效率和稳定性。
18 2
|
22天前
|
Java 开发者
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选。相比 `synchronized`,Lock 提供了更灵活强大的线程同步机制,包括可中断等待、超时等待、重入锁及读写锁等高级特性,极大提升了多线程应用的性能和可靠性。通过示例对比,可以看出 Lock 接口通过 `lock()` 和 `unlock()` 明确管理锁的获取和释放,避免死锁风险,并支持公平锁选择和条件变量,使其在高并发场景下更具优势。掌握 Lock 接口将助力开发者构建更高效、可靠的多线程应用。
18 2
|
22天前
|
Java
多线程同步新姿势:Lock接口助你“一统江湖”!
多线程同步新姿势:Lock接口助你“一统江湖”!
38 2
|
22天前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
Java多线程同步实战:从synchronized到Lock的进化之路!
83 1
|
4月前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
164 3
|
4月前
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。
178 3
|
9天前
|
安全 程序员 编译器
C#一分钟浅谈:泛型编程基础
在现代软件开发中,泛型编程是一项关键技能,它使开发者能够编写类型安全且可重用的代码。C# 自 2.0 版本起支持泛型编程,本文将从基础概念入手,逐步深入探讨 C# 中的泛型,并通过具体实例帮助理解常见问题及其解决方法。泛型通过类型参数替代具体类型,提高了代码复用性和类型安全性,减少了运行时性能开销。文章详细介绍了如何定义泛型类和方法,并讨论了常见的易错点及解决方案,帮助读者更好地掌握这一技术。
24 11