zoukankan      html  css  js  c++  java
  • 线程同步

     对于线程来说,完全执行自己的数据,而不必访问任何种类的共享数据,这样的线程非常罕见。例如系统中的所有线程都必须访问系统资源,为了防止共享资源被多个线程破坏,编程人员必须在代码中使用线程同步构造。Windows和CLR提供了许多线程同步构造,许多CLR的线程同步构造实际上就是面向对象的类包装器(wrapper),他们包装了Win32中的线程同步构造,毕竟CLR线程就是Windows线程,这意味着Windows调度并控制着线程的同步。

         当线程调用一个互锁方法时,CPU应强制高速缓存一致性。因此如果我们通过互锁方法操作变量的话,所有的线程同步锁(包括:Monitor,ReaderWriterLock,Mutex,Semaphore,AutoResetEvent,ManualResetEvent等)都将内部调用互锁方法。

         互锁方法

         以线程安全的方式操作数据的最快方法就是使用互锁方法。System.Threading.Interlocked类定义了一组静态方法来支持互锁,这些方法可以以线程安全的方式自动的修改变量。

         Monitor类和lock方法

         微软提供类Monitor类实现互锁,并提供了lock来进行了该类的封装,使其更加好用。在使用lock方法进行互锁时,参数不应给为this,这样会出现公开锁问题。应该定义一个私有的Object字段成员,并构建对象,然后以私有Object的引用为参数使用lock语句。示例代码:

    internal sealed class TransactionWithLockObject {
    // 分配一个用于加锁的private对象m_lock
    private Object m_lock = new Object();
    // 下述字段标识最后一次事务处理执行的时间
    private DateTime timeOfLastTransaction;
    public void PerformTransaction() {
    lock (m_lock) { //对私有字段加锁

    // 执行事物处理
    // 记录最近一次事物处理的时间
    timeOfLastTransaction = DateTime.Now;
    } // 对私有对象解锁
    }
    // 下述属性返回最后一次事务处理执行的时间
    public DateTime LastTransaction {
    get {
    lock (m_lock) { // 对私有字段对象加锁

    return timeOfLastTransaction; //
    } // 解锁
    }
    }
    }

         托管代码中的Windows内核对象

         Windows提供了若干个只用于线程同步的内核对象,这些内核对象包括:互斥体、信号量、事件。Monitor和ReaderWriterLock方法只允许线程的同步在同一个应用程序域内,而内核对象可以同步运行于不同应用程序域或者不同进程中的线程。为此,在创建内核对象时,我们可以将它关联一个安全权限来表示什么人可以操作内核对象。无论何时,只要线程等待内核对象,线程必须从用户模式转为内核模式,导致线程产生性能损失。由于这个原因,通过内核对象来进行线程同步是最慢的一种同步线程方式。

         单个对象收到信号时调用方法

         有时候应用程序生成线程,只是为了等待一个单个的内核对象收到信号,只是为了等待一个单个的内核对象收到信号。一旦对象收到信号,线程就会为另一个线程提交一些通知,然后循环返回,等待这个对象再次收到信号。在这种情况下,线程池是一个很好的办法。

         内核对象收到信号时,为了让线程池中的线程调用回调方法,可以调用System.Threading.ThreadPool类的静态方法RegisterWaitForSingleObject。示例代码:

    using System;
    using System.Threading;
    public static class Program {
    public static void Main() {

    AutoResetEvent are = new AutoResetEvent(false);
    // 告诉线程池等待AutoResetEvent 对象
    RegisteredWaitHandle rwh = ThreadPool.RegisterWaitForSingleObject(
    are, // 等待AutoResetEvent 对象
    EventOperation, // 回调方法

    null, // 将null传递给EventOperation
    5000, // 用5秒钟等待事件发送信号

    false); // 每一次当事件的信号被发送后都调用EventOperaton

    // 进入循环
    Char operation;
    do {
    Console.WriteLine("S=Signal, Q=Quit?") ;
    operation = Char.ToUpper(Console.ReadKey(true).KeyChar);
    if (operation == 'S') {
    // 用户希望发送事件

    are.Set();
    }
    } while (operation != 'Q');
    // 告诉线程池停止等待事件

    rwh.Unregister(null);
    }
    // 一旦事件的信号被发送,或者最后一个信号或超时值已经过去了5秒钟,就调用这个方法
    private static void EventOperation(Object state, Boolean timedOut) {
    if (timedOut) {
    Console.WriteLine("Timedout while waiting for the AutoResetEvent.");
    } else {
    Console.WriteLine("The AutoResetEvent became signaled.");
    }
    }
    }

  • 相关阅读:
    20169210《Linux内核原理与分析》第十周作业
    Collabtive 系统 SQL 注入实验(补充)
    20169211《Linux内核原理与分析》课程总结
    20169211《Linux内核原理及分析》第十二周作业
    20169211 《Linux内核原理与分析》第十一周作业
    20169211《Linux内核原理与分析》 第十周作业
    20169211《Linux内核原理与分析》 第九周作业
    20169210《Linux内核原理与分析》第八周作业
    20169211《linux内核原理与分析》第七周作业
    20169211《Linux内核原理与分析》第六周作业
  • 原文地址:https://www.cnblogs.com/jyz/p/1291066.html
Copyright © 2011-2022 走看看