Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 复制后,引用的数据将重置为其默认值_C#_Multithreading_Locking_Data Sharing - Fatal编程技术网

C# 复制后,引用的数据将重置为其默认值

C# 复制后,引用的数据将重置为其默认值,c#,multithreading,locking,data-sharing,C#,Multithreading,Locking,Data Sharing,我有一个数据似乎被重置为默认值的问题。 该类如下所示(ObjectId是一个简单的枚举): 下面的代码创建该对象。它在特定的线程中运行,比如说Thread1 class Class1 { EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset); public event EventHandler<Output_args> newOutput; public void readInput(){

我有一个数据似乎被重置为默认值的问题。 该类如下所示(ObjectId是一个简单的枚举):

下面的代码创建该对象。它在特定的线程中运行,比如说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) { }
    }
}
}
调用Class2的eventhandler“newOutput”时,调试器会显示副本按预期工作,并为“entrytime”提供预期的刻度数。
但是,当处理器方法想要读取“entrytime”时,其值为0。所有其他字段也有其默认值。
我尝试用long类型的简单字段替换对象“lastoutput”,并移除了锁,但结果是一样的:它在“newOutput”中被正确分配,但在processor方法中有其默认值(0)


您知道为什么会发生这种情况吗?

您不应该锁定对象
lastoutput
,而是锁定另一个对象,因为您重新指定了字段

处理器启动并锁定默认字段实例
新输出参数()
用默认值初始化

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
            }
        }
    }
}
但如果消费者的速度比生产者慢,这将丢弃最后输出。如果需要,可以使用队列(或其他集合)作为缓冲区

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
                }
            }
        }
    }
}
类2{
专用队列输出=新队列();
public void newOutput(对象发送器、输出参数){
锁定(输出){
outputs.Enqueue(args.Copy());
}
}
公共空处理器(){
锁定(输出){
如果(outputs.Count>0){
var lastoutput=outputs.Dequeue();
if(lastoutput.entrytime+10000000>System.DateTime.Now.Ticks){
//做点什么
}
}
}
}
}

演示:

一个简化的工作示例代码就好了。你确定它是Class2的同一个实例吗?我运行了2个实例,而eventhandler只添加到了1个实例中,这让我很困惑。现在修好了,所以thnx!这些似乎只是在链中添加了一个额外的引用。不管怎样,我都尝试过这个解决方案,结果出现了一些有趣的事情。队列列表接收所有输出,但在处理器循环中,计数保持为0。看起来它们是两个不同的对象,但在VisualStudio中,当选择其中一个时,它会高亮显示这两个变量,显示它们是相同的。我将检查是否有2个实例正在运行,但我对此表示怀疑。而且我只对最新的输出感兴趣。其他的可以忽略。
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
            }
        }
    }
}
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
                }
            }
        }
    }
}