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 人が次のコードを持っています。プロセッサ メソッドは、カメラフィードのスレッドで実行されます。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
             }
        }
    }
}

Class2 のイベント ハンドラ 'newOutput' が呼び出されると、デバッガはコピーが期待どおりに機能し、'entrytime' に期待されるティック数が与えられることを示します。
ただし、プロセッサ メソッドが「entrytime」を読み取りたい場合、その値は 0 です。他のすべてのフィールドにもデフォルト値が割り当てられています。
オブジェクト「lastoutput」を long 型の単純なフィールドに置き換えてロックを削除しようとしましたが、結果は同じです。「newOutput」で適切に割り当てられますが、プロセッサ メソッドでデフォルト値 (0) を持ちます。

なぜこれが起こっているのかについてのアイデアはありますか?

4

1 に答える 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
            }
        }
    }
}

ただし、消費者が生産者よりも遅い場合、これは lastoutput を破棄します。必要に応じて、キュー (または別のコレクション) をバッファーとして使用できます。

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

デモ: https://dotnetfiddle.net/daHVD1

于 2014-09-01T14:26:21.880 に答える