Ich habe einen Multithreading-Algorithmus entwickelt, und ich habe einige Zweifel über die Freigabe eines Klassenmembers zwischen Threads in C#.C#: Freigeben eines Klassenmembers zwischen Threads
Nehmen wir an, wir haben zwei Klassen Algorithmus und Prozessor. Prozessor hat eine Hauptmethode DoWork und zusätzliche AvalableResources Methode, die gelegentlich aufgerufen wird, um die Anzahl der verfügbaren Ressourcen für die Verarbeitung zu ändern. Die Methoden Run und UpdateResources in Algorithm Objekt werden durch zwei verschiedenen Threads aufgerufen, möglicherweise auf verschiedenen Kernen arbeiten.
Ist es möglich, die variable _processor wird in CPU-Cache gespeichert werden und wird nie in den Speicher geladen werden, und AvaliableResources würde nie genannt werden, weil _processor für den zweiten Thread null ist?
class Processor
{
public void DoWork() { ... }
public void AvaliableResources(int x) { ... }
}
class Algorithm
{
private Processor _processor;
public void Run()
{
_processor = new Processor();
_processor.DoWork();
_processor = null;
}
public void UpdateResources(int x)
{
_processor?.AvaliableResources(x);
}
}
Wenn ein Synchronisationsproblem ist würde der folgende Code eine Lösung für sie sein?
Alternative 1
class Processor
{
public void DoWork() { ... }
public void UpdateResources(int x) { ... }
}
class Algorithm
{
private volatile Processor _processor; // added volatile keyword
public void Run()
{
_processor = new Processor();
_processor.DoWork();
_processor = null;
}
public void UpdateResources(int x)
{
_processor?.UpdateResources(x);
}
}
Alternative 2
class Processor
{
public void DoWork() { ... }
public void UpdateResources(int x) { ... }
}
class Algorithm
{
private Processor _processor;
public void Run()
{
_processor = new Processor();
Thread.MemoryBarrier(); // Added memory barier
_processor.DoWork();
_processor = null;
}
public void UpdateResources(int x)
{
Thread.MemoryBarrier(); // Added memory barier
_processor?.UpdateResources(x);
}
}
Edit: Wie Sie in den Kommentaren vorgeschlagen haben, lesen Sie besser erklärt Code:
class Processor
{
private int resources = Environment.ProcessorCount;
public void DoWork()
{
/*do some long running job using avaliable resources*/
}
public void UpdateResources(int x)
{
resources = x;
}
}
class Algorithm
{
private volatile Processor _processor;
public void Run()
{
_processor = new Processor();
_processor.DoWork();
_processor = null;
}
public void UpdateResources(int x)
{
_processor?.UpdateResources(x);
}
}
class Program
{
static void Main(string[] args)
{
var algorithm = new Algorithm();
var result = Task.Run(() => algorithm.Run());
// The resources were required for other staff and are reduced
algorithm.UpdateResources(1);
// The resources are reassigned for the long running algorithm
algorithm.UpdateResources(10);
// wait until the algorithm finishes
result.Wait();
// this update should have no effect as the Run method has finished and _processor is null
algorithm.UpdateResources(10);
}
}
Was passiert, wenn Sie den Code ausführen? – Fabulous
Beachten Sie auch, wenn https://stackoverflow.com/questions/3556351/why-we-need-thread-memorybarrier Ihre Anfrage – Fabulous
"für den zweiten Thread" nicht adressiert - keiner der Threads ist der erste oder der zweite - sie sind einfach verschiedene Fäden; der "zweite" Thread könnte alles getan haben, bevor 'Run' aufgerufen wurde ... In diesem Fall: Was ist der Wert von' _processor'? –