首页 > 解决方案 > 为什么多线程程序需要锁定令牌

问题描述

下面是一个例子

public class Printer
{
    // Lock token.
    private object threadLock = new object();
    public void PrintNumbers()
    {
       // Use the lock token.
       lock (threadLock)
       {
           ...
       }
    }
}

但是我仍然没有得到线程令牌的概念,为什么有必要?线程令牌与C中的信号量相同吗?但是对于 C 程序,信号量只是一个整数?

标签: c#.netclr

解决方案


lock是一个互斥体,像 POSIXpthread_mutex_lockpthread_mutex_unlockC一样工作。

一次只允许一段代码获取给定对象上的锁,因此这是一种同步线程的方式(不一定是最好的方式,但这是一个更详细和高度上下文相关的答案)。


例如,以下代码同时运行几个线程:

  • 将数字数组的每个元素递增 10,
  • 另一个打印数组的内容
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

Task.WhenAll(
  Task.Run(() =>
  {
    for (var i = 0; i < 10; i++)
    {
      numbers[i] += 10;
      Thread.Sleep(10);
    }
  }),
  Task.Run(() =>
  {
    foreach (var i in numbers)
    {
      Console.Write(i + " ");
      Thread.Sleep(10);
    }
  })
);

由于它们同时运行,因此输出类似于:

11 2 13 4 5 6 7 18 9 10

有些数字会增加,有些则不会,而且每次都不同。

但是,将循环包裹在锁中的相同代码:

object threadLock = new object();
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

Task.WhenAll(
  Task.Run(() =>
  {
    lock (threadLock)
    {
      for (var i = 0; i < 10; i++)
      {
        numbers[i] += 10;
        Thread.Sleep(10);
      }
    }
  }),
  Task.Run(() =>
  {
    lock (threadLock)
    {
      foreach (var i in numbers)
      {
        Console.Write(i + " ");
        Thread.Sleep(10);
      }
    }
  })
);

这只会输出两件事之一,具体取决于哪个循环首先获取锁:

11 12 13 14 15 16 17 18 19 20

或者

1 2 3 4 5 6 7 8 9 10

这两个任务之间没有实际的协调,所以你得到哪个集合(增加或不增加)只取决于哪个首先获得锁。


推荐阅读