• 线程基础篇-线程同步


    Lock是将一段代码定义为临界区,临界区中的代码在同一时刻只能有一个线程访问,

    当临界区代码执行时,其他线程调用会被阻塞,需等待资源释放。

    语法:

    private object locker=new object();

    void Method()

    {

           lock(locker)

           {

                  代码块…

    }

    }

    注意:

    1 lock不能锁定空值

    2 lock不能string类型,因为字符驻留机制,无法被释放

    3 lock不能锁定值类型

    4 lock避免锁定public类型或不受程序控制的对象,容易出现死锁

    实例

     基础类

     1  class CTest
     2     {
     3         private bool deadlocked = true;
     4         private object locker = new object();
     5         public void LockMe(object o)
     6         {
     7             lock(locker)
     8             {
     9                 while(deadlocked)
    10                 {
    11                     deadlocked=(bool)o;
    12                     Console.WriteLine("Foo:I am locked :(");
    13                     Thread.Sleep(500);
    14                 }
    15             }
    16         }
    17         public void DoNotLockMe()
    18         {
    19             Console.WriteLine("I am not locked:)");
    20         }
    21     }
    View Code

    操作

     1 static void Main(string[] args)
     2         {
     3             CTest c1 = new CTest();
     4             Thread th = new Thread(c1.LockMe);
     5             th.Start(true);
     6             Thread.Sleep(100);
     7             lock (c1)
     8             {
     9                 c1.DoNotLockMe();
    10                 c1.LockMe(false);
    11             }
    12             Console.ReadKey();
    13         }
    View Code

    显示效果:

    Monitor

    lcok的底层是Monitor.Enter和Moniter.Exit,有了lock语法糖可以轻松实现加锁操作,为了更精确的操作,需要使用Monitor类

    Monitor.Enter 上锁,锁定资源

    Monitor.TryEnter 在指定超时时间内锁定资源,可避免死锁

    Monitor.Wait  暂时释放资源

    Monitor.Pulse  唤醒等待队列中的线程

    Monitor.Exit  释放资源

    实例:

    打印奇偶数方法

     1       public void PrintEven()
     2         {
     3             Monitor.Enter(this);
     4             try
     5             {
     6                 for (int i = 0; i <= 10; i = i + 2)
     7                 {
     8                     Console.WriteLine(Thread.CurrentThread.Name + "------" + i);
     9                 }
    10             }
    11             catch (Exception)
    12             {
    13 
    14                 throw;
    15             }
    16             finally
    17             {
    18                 Monitor.Exit(this);
    19             }
    20         }
    21 
    22         public void PrintOdd()
    23         {
    24             Monitor.Enter(this);
    25             try
    26             {
    27                 for (int i = 1; i <= 10; i = i + 2)
    28                 {
    29                     Console.WriteLine(Thread.CurrentThread.Name + "------" + i);
    30                 }
    31             }
    32             catch (Exception)
    33             {
    34 
    35                 throw;
    36             }
    37             finally
    38             {
    39                 Monitor.Exit(this);
    40             }
    41 
    42         }
    View Code

    操作

     1       static void Main(string[] args)
     2         {
     3 
     4             Program p = new Program();
     5             Thread the = new Thread(p.PrintEven);
     6             the.IsBackground = true;
     7             the.Name = "打印偶数";
     8             the.Start();
     9             Thread tho = new Thread(p.PrintOdd);
    10             tho.IsBackground = true;
    11             tho.Name = "打印奇数";
    12             tho.Start();
    13          
    14             Console.ReadKey();
    15         }
    View Code

     显示效果:

    ReaderWriterLock

    主要解决类似数据库这种读取数据多写入数据少的情况,如用Monitor类则形成独占,不能实现多个线程读取数据,读写锁很好的解决了这一情况

    主要包括以下几个方法:

    AcquireReaderLock 获取读取锁

    ReleaseReaderLock 释放读取锁

    AcquireWriterLock 获取写入锁

    ReleaseWriterLock 释放写入锁

    UpgradeToWriterLock 读锁转换为写锁

    DowngradeFromWriterLock 写锁转换为读锁

    Mutex

    跨多个线程同步访问的类,只有一个线程能获得互斥锁定,访问受互斥保护的同步代码区域。

    WaitOne 等待资源释放

    ReleaseMutex 释放资源

    最常用的是程序启动时判断是否已有实例在运行

    代码如下:

     1        static void Main()
     2         {
     3             bool flag = false;
     4             bool requestInitialOwnership = true;
     5             Mutex mt = new Mutex(requestInitialOwnership, "MutexTest1", out flag);
     6             if (flag)
     7             {
     8                 Application.EnableVisualStyles();
     9                 Application.SetCompatibleTextRenderingDefault(false);
    10                 Application.Run(new Form1());
    11                 
    12             }
    13             else
    14             {
    15                 MessageBox.Show("MutexTest1已启动");
    16                 Application.Exit();
    17             }
    18             
    19         }
    View Code

    显示效果:

    排队买票,同一窗口在同一时间只能有一个人买票

     买票方法

     1         private static Mutex mt = new Mutex();
     2         public static void buyTichets(Object name)
     3         {
     4             if (mt.WaitOne())
     5             {
     6                 try
     7                 {
     8                     Console.WriteLine("{0}占用窗口并开始买票",name);
     9                     Thread.Sleep(1000);
    10                 }
    11                 catch (Exception)
    12                 {
    13 
    14                     throw;
    15                 }
    16                 finally
    17                 {
    18                     Console.WriteLine("{0}离开窗口",name);
    19                     mt.ReleaseMutex();
    20                 }
    21             }
    22         }  
    View Code

    操作

    1       static void Main(string[] args)
    2         {
    3             Thread th1 = new Thread(buyTichets);
    4             th1.Start("小明");
    5             Thread th2 = new Thread(buyTichets);
    6             th2.Start("小A");
    7             Console.ReadKey();
    8         }
    View Code

    显示效果:

    Interlocked 

    为多线程共享整数变量提供原子操作,类似操作系统的PV操作

    Interlocked.Read 读取计数器的值

    Interlocked.Add 使计数器增加指定的值

    Interlocked.Increment 使计数器加一

    Interlocked.Decrement 使计数器减一

    Interlocked.Exchange  把计数器设定为某个指定值

    Interlocked.CompareExchange 将计数器与某个值比较,若相等则计数器设定为指定的值

    实例

     1         private static char buffer;
     2         private static long used = 0;
     3         static void Main(string[] args)
     4         {
     5             string str = "壬戌之秋,七月既望,苏子与客泛舟游于赤壁之下。清风徐来,水波不兴。举酒属客,诵明月之诗,歌窈窕之章。";
     6             Thread thWriter=new Thread(delegate()
     7             {
     8                 for (int i = 0; i < str.Length; i++)
     9                 {
    10                     while (Interlocked.Read(ref used) == 1)
    11                     {
    12                         Thread.Sleep(50);
    13                     }
    14                     buffer = str[i];
    15                     Interlocked.Increment(ref used);
    16                 }
    17                
    18             });
    19             Thread thReader = new Thread(delegate ()
    20               {
    21                   for (int i = 0; i < str.Length; i++)
    22                   {
    23                       while (Interlocked.Read(ref used) == 0)
    24                       {
    25                           Thread.Sleep(50);
    26                       }
    27                       char ch = buffer;
    28                       Console.Write(ch);
    29                       Interlocked.Decrement(ref used);
    30                   }
    31               });
    32             thWriter.Start();
    33             thReader.Start();
    34             Console.ReadKey();
    35         }
    View Code

    显示效果:文字会一个一个的打印出来,并且不会乱。

      

    AutoResetEvent ManualResetEvent

    实现线程通信,类似信号量Semaphore

    Set()  将信号状态设置为有信号

    Reset() 将信号状态设置为无信号

    WaitOne()  无信号时线程阻塞,有信号时线程无阻塞

    AutoResetEvent和ManualResetEvent的区别在于WaitOne方法,AutoResetEvent的WaitOne会自动改变事件对象的状态,每次只能唤醒一个线程。

  • 相关阅读:
    谈URL中末尾斜杠对SEO的影响
    ORDER BY一个较高级的用法
    MYSQL5.5 提示 Mysq error:Cannot load from mysql.proc
    mysql 数据库信息泄露
    [转]PclZip简介与使用
    通过telnet命令查看memcache运行状态
    [转载]PHP上传问题总结(文件大小检测,大文件上传)
    Silex 基于Symfony2组件的微型框架
    [转]推荐一些不错的计算机书籍
    [转]Beanstalkd简介(job生命周期)
  • 原文地址:https://www.cnblogs.com/arvinzd/p/14445001.html
Copyright © 2020-2023  润新知