申し訳ありませんが、このトピックが完全に終わったことを知っています (私はこれを読んだ、これとこれを読んだ、その他いくつかを読んだ) が、「正しく」行う方法がわからない問題が 1 つあります。
現在、マルチスレッド数独戦略のコードは次のとおりです。
public class MultithreadedStrategy : ISudokuSolverStrategy
{
private Sudoku Sudoku;
private List<Thread> ThreadList = new List<Thread>();
private Object solvedLocker = new Object();
private bool _solved;
public bool Solved // This is slow!
{
get
{
lock (solvedLocker)
{
return _solved;
}
}
set
{
lock (solvedLocker)
{
_solved = value;
}
}
}
private int threads;
private ConcurrentQueue<Node> queue = new ConcurrentQueue<Node>();
public MultithreadedStrategy(int t)
{
threads = t;
Solved = false;
}
public Sudoku Solve(Sudoku sudoku)
{
// It seems concevable to me that there may not be
// a starting point where there is only one option.
// Therefore we may need to search multiple trees.
Console.WriteLine("WARNING: This may require a large amount of memory.");
Sudoku = sudoku;
//Throw nodes on queue
int firstPos = Sudoku.FindZero();
foreach (int i in Sudoku.AvailableNumbers(firstPos))
{
Sudoku.Values[firstPos] = i;
queue.Enqueue(new Node(firstPos, i, false, Sudoku));
}
//Setup threads
for (int i = 0; i < threads; i++)
{
ThreadList.Add(new Thread(new ThreadStart(ProcessQueue)));
ThreadList[i].Name = String.Format("Thread {0}", i + 1);
}
//Set them running
foreach (Thread t in ThreadList)
t.Start();
//Wait until solution found (conditional timeout?)
foreach (Thread t in ThreadList)
t.Join();
//Return Sudoku
return Sudoku;
}
public void ProcessQueue()
{
Console.WriteLine("{0} running...",Thread.CurrentThread.Name);
Node currentNode;
while (!Solved) // ACCESSING Solved IS SLOW FIX ME!
{
if (queue.TryDequeue(out currentNode))
{
currentNode.GenerateChildrenAndRecordSudoku();
foreach (Node child in currentNode.Children)
{
queue.Enqueue(child);
}
// Only 1 thread will have the solution (no?)
// so no need to be careful about locking
if (currentNode.CurrentSudoku.Complete())
{
Sudoku = currentNode.CurrentSudoku;
Solved = true;
}
}
}
}
}
(はい、再帰の有無にかかわらず、上記の戦略が変更するBFSを使用してDFSを実行しました)
private bool _solved;
myを aに変更してprivate volatile solved;
、アクセサーを削除できるかどうか疑問に思っていました。私のメソッドはAm I correct?ProcessQueue()
の状態を変更するため、これは悪いことかもしれません。_solved
ブール値がアトミックであることは知っていますが、コンパイラの最適化によって読み取り/書き込みステートメントの順序が乱れることは望ましくありません (特に、書き込みは 1 回しか行われないため)。
基本的に、lock ステートメントにより、この戦略の実行時間が数十秒長くなります。ロックがなければ、非常に高速に実行されます (ただし、DFS 内のメモリ割り当てのため、DFS に比べて比較的低速です)。currentNode.GenerateChildrenAndRecordSudoku()