очень странная и серьезная проблема многопоточного несоответствия c # - PullRequest
2 голосов
/ 27 декабря 2010

У меня очень простая сторожевая программа с 2 потоками.Один поток обновляет длинную переменную, а другой поток читает переменную.и предупредить, если прошло более X секунд с момента последнего обновления.Проблема в том, что иногда (случается один раз в день более или менее) второй поток считывает устаревшее значение переменной.

Иногда это устаревшее значение 3 секунды назад (т.е. первый поток обновил длинную переменную, но через 3 секунды другой поток не получил новое значение)

Я использую блокировкуво избежание проблемы многопоточного кэширования.Я также пробовал Volatile, Interlock, volatileRead и т. Д., Но ничего не помогает.Класс инициируется через программу VB 6 через COM.Программа очень проста, поэтому я думаю, что это ошибка в C # (возможно, связанная с COM).это программа:

Можете ли вы помочь, пожалуйста?

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);
        }
    }
}

Ответы [ 2 ]

3 голосов
/ 27 декабря 2010
        while (WatchdogActive)

Это не работает, WatchdogActive не объявлено volatile . В версии Release переменная, скорее всего, будет сохранена в регистре процессора, она никогда не увидит обновления, которое какой-либо другой поток вносит в переменную. Другими словами, сторожевая собака по-прежнему будет активна, даже если вы ее выключите.

Вы должны использовать ManualResetEvent здесь, его метод WaitOne (int) автоматически позаботится о Sleep () и даст вам гораздо более быстрое завершение потока в качестве бонуса.

Некоторые странные несоответствия. Вы указываете ошибку на 3 секунды, но вы проверяете только на> = 5 секунд. Sleep () длиннее проверки, что позволяет пропускать сбои. Кажется, вам нравятся пустые блоки catch, которые всегда дают большие возможности для кода, который не работает без какой-либо диагностики. Я предполагаю, что мы не смотрим на реальный код, из-за чего трудно увидеть тонкие проблемы с многопоточностью. Работайте исходя из предположения, что это не ошибка в C #.

0 голосов
/ 27 декабря 2010

обычно я использую lock () для изменчивого объекта, который находится в левой части, в этом случае используйте

volatile object lastDate = DateTime.Now.ToBinary();
...
lock(lastDate){...}

И почему вы передаете 'long' вместо DateTime?

...