很奇怪的和严重的多线程不一致问题C#很奇怪、多线程、严重、问题

2023-09-06 07:30:31 作者:∷8知sμδ谓︵

我有2个线程一个非常简单的监视程序。一个线程正在更新长可变的,其它线程读取的变量。并提醒,如果超过X秒的最后一次更新。的问题是,有时(发生每天一次更或更少)的第二线程读取变量的一个过时的值。

有时候是3秒前陈旧的值(即第一个线程更新的长期变量,但在3秒后另一个线程没有得到新的值)

我用的锁,以避免多线程缓存的问题。我也试过挥发,联锁,volatileRead等,但没有什么帮助。类是通过通过COM的VB 6程序启动。该方案是非常简单的,所以我认为这是在C#中的错误(也许COM相关的)。这是程序:

你能帮忙吗?

 公共类看门狗
{
    长lastDate = DateTime.Now.ToBinary();

    私有对象dateLock =新的对象();
    布尔WatchdogActive = TRUE;
    INT WatchdogTimeoutAlert = 5;
    INT WatchdogCheckInterval = 6000;

    私人无效WatchdogThread()
    {
        尝试
        {
            而(WatchdogActive)
            {
                锁定(dateLock)
                {
                    日期时间lastHB = DateTime.FromBinary(lastDate);

                    如果((DateTime.Now.Subtract(lastHB).TotalSeconds> WatchdogTimeoutAlert))
                    {
                        Console.WriteLine(最后的日期是+ lastDate);

                    }
                }
                Thread.sleep代码(WatchdogCheckInterval);
            }
        }
        赶上(例外前)
        {
        }
    }

    私人无效OnHeartbeatArrive(长heartbeatTime)
    {
        锁定(dateLock)
        {
            lastDate = heartbeatTime;
            Console.WriteLine(得到心跳lastDate+ lastDate);
        }
    }
}
 

解决方案

 而(WatchdogActive)
 

这不工作,WatchdogActive未声明的挥发性的。在发布版本的变量,很可能获得存储在CPU寄存器,它永远不会看到一些其它线程进行到可变的更新。换句话说,看门狗仍将有效,即使你把它关闭。

Java编程拾遗 并发编程概述

您应该在这里使用一个ManualResetEvent的,它的WaitOne(int)方法自动处理的睡眠(),并为您提供了一个更快的线程终止作为奖金。

一些奇怪的不一致。你报出故障,3秒,但只检查> = 5秒。睡眠()长于支票,使得有可能错过故障。你似乎很喜欢空的catch块,总是给人为code失败,没有任何诊断工作,巨大的机遇。我猜我们不是在寻找真正的code,这使得它很难看到细微的线程问题。不要从假设的工作,这是不是在C#中的一个错误。

I have a very simple watchdog program with 2 threads. One thread is updating a long variable and the other thread reads the variable. and alert if it was more than X seconds from the last update. The problem is that sometimes (happens once a day more or less) the second thread reads a stale value of the variable.

Sometimes it is stale value from 3 seconds ago (i.e. the first thread updated the long variable but after 3 seconds the other thread didn't get the new value)

I am using lock, in order to avoid multi thread caching problem. I also tried Volatile, Interlock, volatileRead etc but nothing helps. The class is initiated via VB 6 program via COM. The program is very simple, so i think that it is a bug in C# (maybe COM related). this is the program:

Can you help please?

public class WatchDog
{
    long lastDate = DateTime.Now.ToBinary();

    private object dateLock = new object();
    bool WatchdogActive = true;
    int WatchdogTimeoutAlert = 5;
    int WatchdogCheckInterval = 6000;

    private void WatchdogThread()
    {
        try
        {
            while (WatchdogActive)
            {
                lock (dateLock)
                {
                    DateTime lastHB = DateTime.FromBinary(lastDate);

                    if ((DateTime.Now.Subtract(lastHB).TotalSeconds > WatchdogTimeoutAlert))
                    {
                        Console.WriteLine(" last Date is " + lastDate);

                    }
                }
                Thread.Sleep(WatchdogCheckInterval);
            }
        }
        catch (Exception Ex)
        {
        }
    }

    private void OnHeartbeatArrive(long heartbeatTime)
    {
        lock (dateLock)
        {
            lastDate = heartbeatTime;
            Console.WriteLine(" Got Heartbeat lastDate " + lastDate);
        }
    }
}

解决方案

        while (WatchdogActive)

That doesn't work, WatchdogActive isn't declared volatile. In the Release build the variable is very likely to get stored in a CPU register, it never sees the update that some other thread makes to the variable. In other words, the watch dog will still be active, even though you turned it off.

You should use a ManualResetEvent here, its WaitOne(int) method automatically takes care of the Sleep() and gives you a much quicker thread termination as a bonus.

Some strange inconsistencies. You quote a failure at 3 seconds but you only check for >= 5 seconds. The Sleep() is longer than the check, making it possible to miss failures. You seem to like empty catch blocks, always giving great opportunities for code failing to work without any diagnostic. I'm guessing we're not looking at the real code, that makes it difficult to see subtle threading problems. Do work from the assumption that this is not a bug in C#.