C#中使用lock和Monitor控制多线程对资源的使用,最常见的生产者和消费者问题就是多线程同步和通信的经典例子。了解C#多线程的同步与通信。

一、关于lock和Monitor

lock可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其它线程必须等待。格式定义如下:

lock(expression) statement_block

expression代表要跟踪的对象,通常是引用。一般地,如果想保护一个类的实例,使用this;如果保护一个静态变量(如互斥代码段在一个静态方法内部),使用类名就可以了。而statement_block就是互斥段的代码。

Monitor用于多线程公用一个对象时使线程共享资源的方案。Monitor必须和一个具体的对象相关联。

二、生产者和消费者问题

假设两个线程同时维护一个队列,如果一个线程对队列中更新元素,而另外一个线程从队列中获取元素,那么我们称更新元素的线程为生产者,称获取元素的线程为消费者。

1、被操作对象

   /// <summary>;
/// 被操作对象
/// </summary>;
public class Counter
{
//更新和读取的数字
private int numberOfCounter;
//读操作可执行标记,可以防止死锁的发生
private bool readFlag = false; public void Read()
{
//锁定后,其它读操作等待这一次读操作完成
lock (this)
{
//第一次之行为flase,进入等待
if (!readFlag)
{
try
{
//进入等待读,另一个线程写
Monitor.Wait(this);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
} Console.WriteLine("消费(获取): {0}", numberOfCounter); //重置,消费已经完成
readFlag = false;
Monitor.Pulse(this);
}
} public void Write(int number)
{
//锁定后,其它写操作等待这一次写操作完成
lock (this)
{
//第一次readFlag为flase,跳过执行下边的写
//如果当前正在读,等待读操作执行Monitor.Pulse
if (readFlag)
{
try
{
Monitor.Wait(this);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
numberOfCounter = number;
Console.WriteLine("生产(更新): {0}", numberOfCounter); //重置,生产已经完成
readFlag = true; //同步通过等待Pulse来完成
Monitor.Pulse(this);
}
}
}

2、生产者和消费者

   /// <summary>;
/// 生产者
/// </summary>
public class CounterWrite
{
Counter counter;
//生产者生产次数
int quantity = 1; public CounterWrite(Counter box, int request)
{
//构造函数
counter = box;
quantity = request;
} //生产者向操作对象更新信息
public void Write()
{
for (int i = 1; i &lt;= quantity; i++)
counter.Write(i);
}
} /// <summary>
/// 消费者
/// </summary>
public class CounterRead
{
Counter counter;
//生产者生产次数
int quantity = 1; public CounterRead(Counter box, int request)
{
//构造函数
counter = box;
quantity = request;
} //消费者从操作对象中获取信息
public void Read()
{
for (int i = 1; i &lt;= quantity; i++)
counter.Read();
}
}

3、线程操作

       Counter counter = new Counter();

            CounterRead read = new CounterRead(counter, 10);
CounterWrite write = new CounterWrite(counter, 10); Thread th1 = new Thread(new ThreadStart(read.Read));
Thread th2 = new Thread(new ThreadStart(write.Write)); th1.Start();
th2.Start(); th1.Join();
th2.Join(); Console.ReadLine();

通过lock锁定Counter对象的引用,初始readFlag为false控制线程1等待读取:Monitor.Wait(this),
线程2写入,然后更改readFlag,然后执行:Monitor.Pulse(this),通知等待队列中的线程请求对象状态已发生改变,
线程1锁定this,执行读操作,然后更改readFlag,线程1和线程2交互执行写读的操作。
同时因为readFlag的存在和交替更新,避免了死锁情况的发生。

C#多线程的同步与通信的更多相关文章

  1. Python 多线程、多进程 (二)之 多线程、同步、通信

    Python 多线程.多进程 (一)之 源码执行流程.GIL Python 多线程.多进程 (二)之 多线程.同步.通信 Python 多线程.多进程 (三)之 线程进程对比.多线程 一.python ...

  2. Qt 多线程同步与通信

    Qt 多线程同步与通信 1 多线程同步 Qt提供了以下几个类来完成这一点:QMutex.QMutexLocker.QSemphore.QWaitCondition. 当然可能还包含QReadWrite ...

  3. JAVASE02-Unit010: 多线程基础 、 TCP通信

    多线程基础 . TCP通信 * 当一个方法被synchronized修饰后,那么 * 该方法称为同步方法,即:多个线程不能同时 * 进入到方法内部执行. package day10; /** * 当多 ...

  4. 转载自~浮云比翼:Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)

    Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)   介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可 ...

  5. Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)

    介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可以看作是Unix进程的表亲,同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间, ...

  6. Java多线程之线程的通信

    Java多线程之线程的通信 在总结多线程通信前先介绍一个概念:锁池.线程因为未拿到锁标记而发生的阻塞不同于前面五个基本状态中的阻塞,称为锁池.每个对象都有自己的锁池的空间,用于放置等待运行的线程.这些 ...

  7. java多线程与线程间通信

    转自(http://blog.csdn.net/jerrying0203/article/details/45563947) 本文学习并总结java多线程与线程间通信的原理和方法,内容涉及java线程 ...

  8. java第五节 多线程/多线程的同步

    /* 第五讲 多线程 了解进程和线程 在多任务系统中,每个独立执行的程序称为进程,也就是"正在进行的程序",我们现在使用的操作系统一般都是多任务的 即能够同时执行多个应用程序,实际 ...

  9. 扯扯python的多线程的同步锁 Lock RLock Semaphore Event Condition

    我想大家都知道python的gil限制,记得刚玩python那会,知道了有pypy和Cpython这样的解释器,当时听说是很猛,也就意味肯定是突破了gil的限制,最后经过多方面测试才知道,还是那德行… ...

随机推荐

  1. Mycat高可用解决方案一(mysql安装)

    Mycat高可用解决方案一(mysql安装) Mycat关键特性 关键特性 支持SQL92标准 支持MySQL.Oracle.DB2.SQL Server.PostgreSQL等DB的常见SQL语法 ...

  2. 是否忘记了向源中添加“#include "StdAfx.h"”?

    错误分析 此错误发生的原因是编译器在寻找预编译指示头文件(默认#include "stdafx.h")时,文件未预期结束.没有找到预编译指示信息的头文件"stdafx.h ...

  3. Python与设计模式之单例模式

    一.什么是单例 即单个实例,指的是同一个类实例化多次的结果指向同一个对象,用于节省内存空间 如果我们从配置文件中读取配置来进行实例化,在配置相同的情况下,就没必要重复产生对象浪费内存了 # setti ...

  4. 03、磁盘管理+swap分区创建+磁盘配额+自动挂载

    磁盘管理 分区标识 一般用4位标识,前两位,磁盘类型,第3位,磁盘编号,第4位,分区编号 如: /dev/sda1     sd  磁盘类型    a  磁盘编号   1  分区编号 [root@s1 ...

  5. Oracle ASMCMD命令参考

    Oracle ASMCMD命令参考 0.什么是asm ASM它提供了以平台无关的文件系统.逻辑卷管理以及软RAID服务.ASM可以支持条带化和磁盘镜像,从而实现了在数据库被加载的情况下添加或移除磁盘以 ...

  6. 重新编译kubeadm,修改默认证书时间

    参考 kubeadm alpha certs renew Kubeadm1.14 证书调整 kubeadm 部署的 kubernetes 集群,默认的证书有效时间是1年,需要每年手工更新. 1. 重新 ...

  7. 如何使用离线存储(localStorage)?

    1.存储数据:localStorage.setItem("属性","属性值") 2.获取本地存储的值:localStorage.getItem("属性 ...

  8. python总结一

    1. python中的而标准数据类型: number(数字) string(字符串) list(列表) tuple(元祖) dic(字典) 其中数字类型有: python支持四种不同的数字类型: in ...

  9. java面试题——高级篇

    一.集合 Hashmap的原理 源码分析参考文章:http://www.cnblogs.com/xwdreamer/archive/2012/06/03/2532832.html 题目参考文章:htt ...

  10. 【操作系统之四】Linux常用命令之awk

    一.概念awk是一个报告生成器,拥有强大的文本格式化能力. 数据可以来自标准输入(stdin).一个或多个文件,或其它命令的输出: 依次对每一行进行处理,然后输出: 它在命令行中使用,但更多是作为脚本 ...