2

BackgroundWorkerなんらかの理由で代替を実装していますが、次のパブリック プロパティを実装する必要があります。

public bool CancellationPending { get; private set; }
public bool IsBusy { get; private set; }
public bool WorkerReportsProgress { get; set; }
public bool WorkerSupportsCancellation { get; set; }

彼らがどのような目的を果たしているのか、あなたは知っていると思いますBackgroundWorker。したがって、それらは異なるスレッドによってアクセス/変更される可能性があります。マルチスレッドのためにそれらを「保護」する方法が心配です。volatileとして宣言すれば十分だと思いましたvolatileが、自動プロパティには適用できません。

私は何をすべきか?これらのプロパティのプライベート フィールドを作成して宣言する必要がありますvolatileか? または、各およびブロックlock内で ingを使用する必要がありますか?getset

これは非常に一般的なシナリオであると思います-プロパティ(できれば自動プロパティ)をスレッドセーフにします。この例では、すべてのプロパティがアトミック型であることに注意してください。

編集:

必要なものを明確にするために、すべてのスレッドが常にプロパティの最新の値を読み取るようにする必要があります。これを参照してください: https://stackoverflow.com/a/10797326/1081467

volatile繰り返しますが、 、またはlocking 、または何か他のものを使用することをお勧めしますか? ..boolプロパティを使用する場合、原子性が保証されているため、2番目の問題 (最新の値を読み取る) だけが残っているため、これを正しく解決するにはどうすればよいですか? ? 非プリミティブ型のプロパティがある場合はどうなりますか? lockそれぞれgetsetブロックにsを入れますか?

4

4 に答える 4

6

私は次の実装を思いついた。それが最適な解決策だと思うかどうかコメントしてください:

//========== Public properties ==================================================//

public bool CancellationPending { get { return _cancellationPending; } private set { _cancellationPending = value; } }

public bool IsBusy { get { return _isBusy; } private set { _isBusy = value; } }

public bool WorkerReportsProgress { get { return _workerReportsProgress; } set { _workerReportsProgress = value; } }

public bool WorkerSupportsCancellation { get { return _workerSupportsCancellation; } set { _workerSupportsCancellation = value; } }

//========== Private fields ==================================================//

private volatile bool _cancellationPending;
private volatile bool _isBusy;
private volatile bool _workerReportsProgress;
private volatile bool _workerSupportsCancellation;

理由:原子性は、フィールドがタイプであるという事実によって保証されるため、 ingboolの必要はありません。lockそれらを作成するvolatileと、別のスレッドが変更した場合に、すべてのスレッドが現在の値を読み取ることが保証されます(キャッシュされません)。volatileこれがキーワードの正確な目的(そして唯一の有効な使用法)だと思いますよね?

于 2012-09-12T08:23:25.817 に答える
3
public bool CancellationPending { get; private set; }
public bool IsBusy { get; private set; }
public bool WorkerReportsProgress { get; set; }
public bool WorkerSupportsCancellation { get; set; }

したがって、それらは異なるスレッドによってアクセス/変更される可能性があります

いいえ、それは と にのみ適用されCancellationPendingIsBusy他のものには適用されません。
そして、それらはすべてブール値であり、アトミックであることが保証されています。ここでは原子性で十分です。

元の Backgroundworker のすべてのプロパティは、スレッドセーフではないと文書化されています。このページ
の下部付近を参照してください。

于 2012-09-11T15:50:06.373 に答える
1

svickが述べたように、タスクを別のスケジューラで使用するなど、より良いオプションがあると思いますが。

このパスを続行したい場合は、volatile フィールドではなくロックを確実に使用する必要がありますああ、この男は揮発性フィールドを作成しないことについて何かを言った...

volatile の代わりに、アクセスの特性に応じて、お気に入りの同期プリミティブ (lock、Mutex、Interlocked、ReaderWriterLockSlim など) を使用できます。

于 2012-09-11T15:58:27.703 に答える
0

簡単な方法は、スレッド セーフにするプロパティごとにミューテックス オブジェクトを用意することです。get プロパティと set プロパティで、Monitor.Enter(declaredObjectMutex) と Monitor.Exit(declaredObjectMutex) を使用します。完了すると、プロパティがスレッドセーフになります (get および set のすべての呼び出しは、他のスレッドが終了するまで呼び出しをブロックします)。

もう 1 つのオプションは、Interlocked Class を使用することです。これにより、整数とブール値のスレッドセーフな変更が可能になります。プロパティで使用しているのはそれだけであれば、簡単な解決策です。

于 2012-09-11T15:53:49.890 に答える