軽量スレッド(ファイバー)用のラウンドロビンスケジューラを作成しようとしています。可能な限り多くの同時にスケジュールされたファイバを処理するには、スケーラビリティが必要です。私はまた、実行ループ以外のスレッドからファイバをスケジュールできるようにする必要があります。また、任意のスレッドからスケジューリングを解除することをお勧めします(ただし、実行ループからスケジューリングを解除できるだけです)。軽量スレッドセーフスケジューラの提案
私の現在のアイデアは、各ファイバーがノードであり、スケジューラーが現在のノードへの参照を保持する循環的な二重リンクリストを持つことです。あなたが見ることができるように
using Interlocked = System.Threading.Interlocked;
public class Thread {
internal Future current_fiber;
public void RunLoop() {
while (true) {
var fiber = current_fiber;
if (fiber == null) {
// block the thread until a fiber is scheduled
continue;
}
if (fiber.Fulfilled)
fiber.Unschedule();
else
fiber.Resume();
//if (current_fiber == fiber) current_fiber = fiber.next;
Interlocked.CompareExchange<Future> (ref current_fiber, fiber.next, fiber);
}
}
}
public abstract class Future {
public bool Fulfilled { get; protected set; }
internal Future previous, next;
// this must be thread-safe
// it inserts this node before thread.current_fiber
// (getting the exact position doesn't matter, as long as the
// chosen nodes haven't been unscheduled)
public void Schedule (Thread thread) {
next = this; // maintain circularity, even if this is the only node
previous = this;
try_again:
var current = Interlocked.CompareExchange<Future> (ref thread.current_fiber, this, null);
if (current == null)
return;
var target = current.previous;
while (target == null) {
// current was unscheduled; negotiate for new current_fiber
var potential = current.next;
var actual = Interlocked.CompareExchange<Future> (ref thread.current_fiber, potential, current);
current = (actual == current? potential : actual);
if (current == null)
goto try_again;
target = current.previous;
}
// I would lock "current" and "target" at this point.
// How can I do this w/o risk of deadlock?
next = current;
previous = target;
target.next = this;
current.previous = this;
}
// this would ideally be thread-safe
public void Unschedule() {
var prev = previous;
if (prev == null) {
// already unscheduled
return;
}
previous = null;
if (next == this) {
next = null;
return;
}
// Again, I would lock "prev" and "next" here
// How can I do this w/o risk of deadlock?
prev.next = next;
next.previous = prev;
}
public abstract void Resume();
}
すると、私の争点は、私はロックの順序を保証することはできませんので、私はデッドロックを危険にさらすことなく、複数のノードをロックすることができないということです。これは私がこれまで持っているものです。または私はできますか?私は、スレッドの競合の量が極端になるため、Threadオブジェクトにグローバルなロックを持たせたくありません。さらに、挿入位置について特に気にしないので、各ノードを個別にロックすると、Schedule()はMonitor.TryEnterのようなものを使用し、ロックされていないノードが見つかるまでリストを歩いていきます。
私が言及した要件を満たしている限り、全体として、私は特定の実装に投資していません。どんなアイデアでも大歓迎です。ありがとう!
EDIT -コメントは、私がwinapi繊維(私はそうではない)について話していると人々が思っていることを示しています。一言で言えば、私がしたいのは、スレッドでのスレッドを1つずつ実行するようにコードをスケジュールすることだけです。これはTPL/Async CTPに似ていますが、AFIKはUIスレッドでない限り、同じスレッドで継続を保証するものではありません。私は上記を実装する方法について別の提案をしていますが、単に「繊維を使用しない」と言ってはいけません。
スレッドプールまたはBackgroundworkerで何が問題になっていますか? –
私はOSレベルのスレッドよりも安価なものを撮影しています。私は何万(またはそれ以上)の繊維を予定しており、自分自身をスケジューリングしスケジューリングすることを望んでいます – chkn
犯罪はありませんが、将来的に私は煩わしさ、痛み、失敗を予見します。私はwinapiにファイバーを書き込もうとしたことは一度もありませんでした。私はこれまでになかったプログラマーやプログラムの数が少なかったと思います。その理由は、ユースケースに合ったプログラムの量が0くらいだからです。すべてのプログラムの000001%。 (それ、私はおそらく技術的な知識が不足している)。 –