如何用C#来演示线程中的lock

348 阅读6分钟

使用C#来演示线程中的锁

锁是为线程获取锁的一个关键词快捷方式。锁定关键字使得在与另一个线程工作时,可以封锁一段代码。

要进入一个已经存在线程的代码段,另一个线程必须等待,直到前一个线程的执行完成。一旦函数中的当前线程完成了,锁就会被释放。

C#中的线程安全是通过监控和锁的方法完成的。一次执行一个代码将缓解编码困难。

前提条件

要跟上本教程,你应该具备以下条件。

  • 关于C#编程语言的背景信息。
  • 对C#中的多线程有一定了解。
  • 安装了[Visual Studio]。

C语言中的线程锁

锁关键字用于为单个线程获得一个锁。一个锁可以防止几个线程同时访问一个资源。

通常情况下,你希望线程能够并发运行。使用C#中的lock ,我们可以防止一个线程改变我们的代码,而另一个线程却这样做。试图使用被解锁的代码将停止线程。

常见的锁结构包括。

  • Mutex
  • 锁定

Mutex vs Lock

需要注意的是,lock是一个编译器关键字,而不是一个类名。如果你想使用Monitor ,但不知道如何使用,这是一个方便的包装器。

MonitorLock 关键字是AppDomain-only 。我们使用一个实例化的对象(内存位置引用)来管理锁并保持监视器的标识。

然而,Mutex ,是对操作系统机制的一个.Net ,用于全系统的同步。突变器是一种用于同步资源访问的锁定技术。对于两个寻址相同数据的mutex,它是同一个操作系统的mutex。

建立锁所需的时间和精力较少。突变锁有一个包含众多计算机进程的功能。

锁的语法

lock(object_name) statement_block

我们将在以下情况下解释其语法。

  • object_name - 这是一个表达式,要锁定的对象是指定的。它必须是一个引用类型的表达式。
  • statement_block - 这指定了获得线程锁后要运行的代码块。

C#中lock关键字的工作

本节将讨论C#中的锁。这是为了学习锁在C#中的运作方式。

  • 使用锁可以限制对一个代码块的并发访问。这是为了防止其他线程的干扰。
  • 为了防止其他线程干扰被锁的线程,它们必须等待或停止,直到它完成。
  • 使用锁来管理线程是更快、更愉快的。
  • 一旦当前线程结束,锁就会被释放,使新鲜的线程能够执行。

C#锁的实现

为了理解锁的实现,让我们先创建一个没有锁的C#线程。下面的代码示例显示了C#中没有锁的多线程。

using System;
using System.Threading;

namespace Threading_without_lock
{
    class lookup
    {
        static void Main(string[] args)
        {
         Thread one = new Thread(PrntChar);
         Thread two = new Thread(PrntChar);
         one.Start();
         two.Start();

         Console.ReadLine();

        }
        public static void PrntChar()
        {
            string strArray = "Hi programmer";

            int y;
            y=0;

                for (y = y; y < strArray.Length; y++)
                {
                    Console.Write($"{strArray[y]}");
                    Thread.Sleep(TimeSpan.FromSeconds(0.1));
                }

            Console.Write(" ");
        }
    }
}

输出。

HHii  pprrooggrraammmmeerr

这个例子利用了两个线程的PrntChar 函数。由于没有锁语句,许多线程将被允许同时使用PrntChar 函数。

现在让我们来看看线程中哪里有锁。

要查看C#锁,在另一个线程运行时执行以下代码。

using System;
using System.Threading;

namespace Threading_with_lock
{
  class lookup
  {
// create a thread named identity
    static readonly object Identity = new object ();
    static void output ()
    {
// Enter the lock to the thread
      lock (Identity)
      {
// initialize the integer to be used in the for loop
	int y;
	  y = 4;
// compute the for loop
	for (y = y; y <= 6; y++)
	  {
// Output string and the value of the lock
	    Console.WriteLine ("The output will be: {0}", y);
	  }
      }
    }
    static void Main (string[]args)
    {
      Thread one = new Thread (output);
      Thread two = new Thread (output);
      one.Start ();
      two.Start ();
      Console.ReadLine ();
    }
  }
}

输出。

The output will be: 4
The output will be: 5
The output will be: 6
The output will be: 4
The output will be: 5
The output will be: 6

前面的程序声明了一个Threading_with_lock 命名空间。之后,生成了一个lookup 类,并建立了一个锁定义的对象。

一个显示方法被创建并与锁一起执行,以防止其他线程干扰当前线程的执行。对象被创建后,关键字lock ,对其进行加密。因为我们在显示方法上使用了锁,所以结果会按顺序出现。

了解C#中的监视器

监控器是一种确定每次只有一个线程可以执行特定部分代码的方法。一个监视器有一个锁,每次只有一个线程可以访问它。

监视器同步对象的访问。可以通过获得一个重要的锁来实现这一点。

监控器与锁类似,但用户可以通过使用监控器函数来调节共享同一代码锁的线程的同步程度。其他线程不能查看所有者的应用代码锁,除非他们使用一个单独的锁定对象来执行它。

监控器类提供了以下方法用于通过锁来同步代码访问。

  • Monitor.Enter
  • Monitor.TryEnter
  • Monitor.Exit

对象而不是值类型被锁定。在这两种情况下,值类型参数都被发送到EnterExit ,但它的打包方式不同。

当被提醒时,Wait 释放锁。一旦被通知,Wait 返回来重新获得锁。等待队列中的下一个线程需要PulsePulseAll 信号。

using System;
using System.Diagnostics;
using System.Threading;
namespace Demo
{
    class Inspect
    {
        public static object locks = new object();

        public static void Values()
        {
            Monitor.Enter(locks);
            try
            {
                for (int z = 1; z <= 4; z++)
                {
                    Thread.Sleep(750);
                    Console.WriteLine(z + "");
                }

            }
            finally
            {
                Monitor.Exit(locks);
            }
        }

        private static void TrialLock()
        {

            lock (locks)
            {
                Thread.Sleep(750);
                Console.WriteLine(DateTime.Now);
            }
        }

        public static void Main(string[] args)
        {

           Thread[] mythread = new Thread[2];
            for (int Op = 0; Op < 2; Op++)
            {
                mythread[Op] = new Thread(new ThreadStart(Values));
                mythread[Op].Name = " " + Op;
            }
            foreach (Thread td in mythread)
                td.Start();

            Console.WriteLine(mythread);
        }
    }
}

输出。

System.Threading.Thread[]
1
2
3
4
1
2
3
4

Inspect 类是静态的,不能被实例化。Inspect 类利用了Monitor.Enter,Monitor.TryEnter, 和Monitor.Exit 方法。

一旦一个代码区被锁定,就可以使用监控器;你可以使用Monitor.Wait,Monitor.Pulse, 和Monitor.PulseAll 方法。按需使用,它被链接到一个特定的对象。它是非绑定的,这意味着它可以从任何地方被调用。

避免使用lock关键字的情况

在下列情况下,不要使用lock 关键字。

  1. 在值类型而不是引用类型上使用锁,会导致编译时的错误。
  2. 为了避免线程死锁,使用私有引用变量而不是这个关键字。
  3. 在字符串对象上--内部的字符串是全局的,可以在你不知情的情况下被其他线程停止运行。避免锁定字符串对象。

结论

一个锁可以防止几个线程同时访问一个资源。它在当前线程结束时被释放,允许其他线程运行。Mutex和monitor是基本的锁结构。