경량 스레드 (파이버) 용 라운드 로빈 스케줄러를 작성하려고합니다. 가능한 한 많은 수의 동시에 계획된 광섬유를 처리 할 수 있도록 확장해야합니다. 나는 또한 실행 루프가 아닌 스레드에서 파이버를 스케줄링 할 수 있어야하며, 임의의 스레드에서도 스케줄링을 취소해야합니다 (실행 루프에서 스케줄을 취소 할 수는 있지만).가벼운 스레드 안전 스케줄러에 대한 제안
나의 현재 아이디어는 각 파이버가 노드이고 스케줄러가 현재 노드에 대한 참조를 보유하는 원형 이중 연결 목록을 갖는 것입니다. 당신이 볼 수 있듯이
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 섬유 (나는 그렇지 않다)에 대해 말하고 있다고 생각합니다. 간단히 말해서, 스레드에서 스레드를 차례로 실행하도록 코드 비트를 예약하는 것입니다. TPL/Async CTP와 비슷하지만 AFIK는 UI 스레드가 아닌 한 같은 스레드에서 연속성을 보장하지 않습니다. 위의 방법을 구현하는 방법에 대한 제안을 대체 할 수 있지만 "섬유를 사용하지 마십시오"라고 말하지 마십시오.
스레드 풀 또는 Backgroundworker에 어떤 문제가 있습니까? –
OS 레벨 스레드보다 저렴한 가격으로 촬영하고 있습니다. 나는 수만 (또는 그 이상)의 섬유를 가지고 일정을 세우고 스케쥴을 잡을 생각을한다. – chkn
불쾌감은 없지만, 미래를 위해 나는 성가심, 불안정, 그리고 실패를 예견한다. 필자는 winapi에 섬유를 쓰려고 시도한 적이 없었습니다. 필자는 의심의 여지없이 적은 양의 프로그래머 및/또는 프로그램이 있다고 의심합니다. 그 이유는 유스 케이스에 맞는 프로그램의 양이 거의 0이되기 때문입니다.모든 프로그램의 000001 %. (기술적 인 지식이 부족한 것 같습니다). –