Ссылочные данные сбрасываются до значений по умолчанию после копирования

1

У меня проблема с данными, которые, похоже, сбрасываются до значений по умолчанию. Класс выглядит следующим образом (objectIDs - простое перечисление):

public class Output_args: EventArgs {
    public objectIDs outputtype;
    public int internalID;
    public int verdict;
    public int outputID;
    public long entrytime;

    public Output_args Copy() {
        Output_args args = new Output_args();
        args.entrytime = this.entrytime;
        args.internalID = this.internalID;
        args.outputID = this.outputID;
        args.outputtype = this.outputtype;
        args.verdict = this.verdict;
        return args;
    }
}

Следующий код создает объект. Он работает в определенном потоке, пусть говорит Thread1.

class Class1 {
EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
public event EventHandler<Output_args> newOutput;
public void readInput(){
    List<Output_args> newoutputlist = new List<Output_args>();
    /* 
    * code to determine the outputs
    */
    Output_args args = new Output_args();
    args.outputtype = objectIDs.stepID;
    args.internalID = step[s].ID;
    args.verdict = verdict;
    args.entrytime = System.DateTime.Now.Ticks;
    newoutputlist.Add(args.Copy());
    if (newOutput != null && newoutputlist.Count > 0) {
    // several outputs are being sent sequentially but for simplicity i've removed the for-loop and decision tree
        try {
            newOutput(null, newoutputlist[0].Copy());
        } catch (Exception) { }
    }
}
}

1 подписчика на это событие имеет следующий код. Метод процессора работает на потоке camerafeed. Обработчик события newOutput запускается в Thread1.

class Class2: Form {
    private Output_args lastoutput = new Output_args();
    public void newOutput(object sender, Output_args args) {
        lock (lastoutput) {
            lastoutput = args.Copy();
        }
    }

    public void processor(){
        lock (lastoutput) {
            if (lastoutput.entrytime + 10000000 > System.DateTime.Now.Ticks) {
            // do something
             }
        }
    }
}

Когда вызывается обработчик событий "newOutput" класса 2, отладчик показывает, что копия работает так, как ожидалось, и "входное время" получает ожидаемое количество тиков.
Однако, когда процессорный метод хочет прочитать "время входа", его значение равно 0. Все остальные поля также имеют назначенное им значение по умолчанию.
Я попытался заменить объект "lastoutput" простым полем типа long и удалил блокировки, но результаты были одинаковыми: он правильно назначается в "newOutput", но имеет значение по умолчанию (0) в методе процессора.

Любые идеи о том, почему это происходит?

  • 0
    Упрощенный рабочий пример кода был бы отличным.
  • 0
    И вы уверены, что это тот же экземпляр Class2?
Показать ещё 1 комментарий
Теги:
multithreading
locking

1 ответ

0

вам не следует блокировать объект lastoutput, но на другом объекте, потому что вы переназначаете это поле.

Процессор запускает и блокирует экземпляр поля по умолчанию new Output_args() инициализированный значениями по умолчанию

class Class2: Form {
    private object mylock = new object();
    private Output_args lastoutput;
    public void newOutput(object sender, Output_args args) {
        lock (mylock) {
            lastoutput = args.Copy();
        }
    }

    public void processor(){
        lock (mylock) {
            if (lastoutput == null) {
               //nothing to consume yet
            }
            else if (lastoutput.entrytime + 10000000 > System.DateTime.Now.Ticks) {
               // do something
            }
        }
    }
}

но это отбрасывает lastouput, если потребитель медленнее производителя. Вы можете использовать очередь (или другую коллекцию) в качестве буфера, если это необходимо.

class Class2 {
    private Queue<Output_args> outputs = new Queue<Output_args>();

    public void newOutput(object sender, Output_args args) {
        lock (outputs) {
            outputs.Enqueue(args.Copy());
        }
    }

    public void processor(){
        lock (outputs) {
            if (outputs.Count > 0) {
                var lastoutput = outputs.Dequeue();

                if (lastoutput.entrytime + 10000000 > System.DateTime.Now.Ticks) {
                // do something
                }
            }
        }
    }
}

demo: https://dotnetfiddle.net/daHVD1

  • 0
    Это, кажется, только добавляет дополнительную ссылку в цепочке. В любом случае, я попробовал это решение, и появилось что-то интересное. Список очереди получает все выходные данные, но в цикле процессора счетчик остается равным 0. Таким образом, кажется, что это 2 разных объекта, но в Visual Studio он выделяет обе переменные, когда выбрана 1 из них, показывая, что они одинаковы. Я собираюсь проверить, есть ли у меня 2 запущенных экземпляра, но я сомневаюсь в этом. Также меня интересует только последняя продукция. Остальные могут быть проигнорированы.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню