【问题标题】:c# Lock with Thread.Sleep not workingc# 用 Thread.Sleep 锁定不工作
【发布时间】:2023-04-06 23:28:02
【问题描述】:

我有以下代码。 在 windows server 2008 中,该程序是正确的并且可以按预期运行。它输出 10 个不同的 id。

但是,当我在 windows server 2003 中运行它时,程序不正确。它输出 10 个 id,但其中一些 id 是重复的。锁好像坏了。

如果我设置Thread.Sleep(500),它在windows server 2003 上可以正常工作。

class Test
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine(Util.GetId());
        }
        Console.ReadLine();
    }
}

public class Util
{
    private static object idlock = new object();

    public static string GetId()
    {
        string id = "";
        lock (idlock)
        {
            Thread.Sleep(1);
            id = System.DateTime.Now.ToString("yyMMddHHmmssffff");
        }
        return id;
    }
}

【问题讨论】:

  • 我认为问题在于:Windows 不是实时操作系统,因此您不会从 Thread.Sleep(1) 获得每秒 1000 次唤醒。如果您没有使用 timeBeginPeriod 设置最小分辨率,您将大约每 15 毫秒唤醒一次。即使您将最小分辨率设置为 1 毫秒,您仍然只会每 3-4 毫秒唤醒一次。为了获得毫秒级计时器粒度,您必须使用 Win32 多媒体计时器(C# 包装器)。
  • 现在,我已将睡眠时间设置为 15,当应用程序在 windows 2003 中运行时问题已解决。但在 windows 2008 中仍然可以正常运行。感谢您的所有回复!

标签: c# datetime locking time-measurement


【解决方案1】:

锁定是完全没有必要的;问题是DateTime.Now 的粒度只有约 15 毫秒左右(取决于您的系统)。一开始就不要把时间当做id;您可以轻松地做这样的事情:

public static class Util
{
    static long _id;
    public static string GetId()
    {
        return Next().ToString("0000000000000000");
    }

    private static long Next()
    {
        return Interlocked.Increment(ref _id);
    }
}

【讨论】:

  • 没错,代码太快了。即使进行更复杂的计算,我也遇到过很多次。
  • 你的方法很棒。但是我的应用程序有几个项目同时使用GetId()方法。上面的代码是一个示例。
  • ...所以使用命名互斥锁而不是 Interlocked.Increment()
【解决方案2】:

虽然我建议不要使用这种生成密钥的方法,但如果您受到其他条件的限制,那么您可以在不强制等待的情况下修复代码的一种方法是保留对最后生成的 id 的引用,然后只生成的 id 仍然匹配旧的, sleep(10) 左右。

这将保留您代码的所有现有属性,我认为主要是它将在程序运行之间保持递增,而不是像其他示例那样的单个会话。

【讨论】:

    【解决方案3】:

    Thread.Sleep 的参数以毫秒为单位,选择一个更大的数字。或者使用 Guid.NewGuid() 生成一个真正唯一的 ID 而不会浪费时间。

    【讨论】:

    • 我知道这个。但是 Guid.NewGuid 不能用来订购。如果选择更大的数字,那就浪费时间。在我的应用程序中,这是我获取 newid 的核心方法。
    • 这段代码会生成一个顺序的Guid:developmenttips.blogspot.com/2008/03/…
    • 我的应用程序运行了几天,sqldata中所有的key id都是通过这个方法得到的。所以我不能替换这个方法。
    【解决方案4】:

    DateTime.Ticks 适合你吗?它有 100 纳秒的分辨率,所以听起来它可以工作。你也不必锁定任何东西,IMO。

    【讨论】:

    • DateTime.Ticks? DateTime 在 System.DateTime 中没有这个属性。
    • 从 1.1 开始就在那里 MSDN says
    • 您忘记了时间变化 - 在秋季,您将看到一个小时内相同的刻度
    • 刻度可能有 100 纳秒的分辨率,但这并不意味着时钟具有这种精度!时钟硬件仅精确到大约 1/64 秒。
    • @dawebber:时钟精度不依赖于硬件; StopWatch 类的精度取决于硬件;它要求芯片提供高分辨率计时器。我认为“挂钟”的精度是基于线程量子的大小。但是忽略所有这些:您无法保证“滴答声”是单调递增的。用户可能会弄​​乱时钟,时间可能会因夏令时而改变,等等。如果你想要一个单调递增的数字自己写一个,不难做到。
    【解决方案5】:

    既然您正在锁定,请尝试保存先前的值,并比较是否相等。如果等于,则不返回,而是在循环中休眠并重试。

    就个人而言,我认为这种方法很糟糕。使用 GUID,它们是你的朋友。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-09
      • 2016-08-17
      • 1970-01-01
      • 1970-01-01
      • 2011-10-17
      • 2018-04-04
      • 2016-03-22
      相关资源
      最近更新 更多