В настоящее время я создаю конвейер для моего симулятора asm. Я сделаю это с многопоточностью. В настоящее время у меня есть четыре потока, которые соответствуют каждой выборке, декодированию, выполнению и обратной записи. Я не понимаю, как правильно кодировать конвейер. Вот часть моего кода:
private void Fetch()
{
while(_continue)
{
fetchEvent.WaitOne();
if (!_continue) break;
lock (irLock)
{
try
{
// Do stuff to fetch instruction...
catch (IndexOutOfRangeException e) { Err = "Segmentation Fault at Line " + _pc.ToString(); }
catch (Exception e) { Err = e.Message + "Line " + _pc.ToString(); }
_pc++;
GiveTurnTo(2); // used these 2 lines to handle mutual exclusion
WaitTurn(1);
}
}
}
private void Decode()
{
while (_continue)
{
decodeEvent.WaitOne();
if (!_continue) break;
lock (irLock)
{
WaitTurn(2);
Console.WriteLine("decode works");
GiveTurnTo(1);
}
}
}
private void Execute()
{
while (_continue)
{
exeEvent.WaitOne();
if (!_continue) break;
lock (irLock)
{
//WaitTurn(3);
Console.WriteLine("Am I, execute, getting a turn?");
// GiveTurnTo(4);
}
}
}
private void WriteBack()
{
while (_continue)
{
wbEvent.WaitOne();
if (!_continue) break;
lock (irLock)
{
Console.WriteLine("Am I, Write Back, getting a turn?");
//GiveTurnTo(1);
// WaitTurn(4);
}
}
}
}
Я использую этот метод для запуска цикла нажатием кнопки:
public void nextInstruction()
{
fetchEvent.Set();
decodeEvent.Set();
exeEvent.Set();
wbEvent.Set();
}
I was thinking of changing nextInstruction() to this:
public void nextInstruction()
{
fetchEvent.Set();
}
При этом каждое нажатие кнопки всегда начинается с «Выбрать». После этого я подумал, что, может быть, я мог бы поместить событие set в методе Fetch для вызова следующей части цикла (Decode) и сделать то же самое для следующих методов. Я бы получил что-то вроде этого:
private void Fetch()
{
while(_continue)
{
// Do stuff....
decodeEvent.Set();
}
}
private void Decode()
{
while (_continue)
{
// Do stuff...
exeEvent.Set();
}
}
private void Execute()
{
while (_continue)
{
// Do stuff...
wbEvent.Set();
}
}
private void WriteBack()
{
while (_continue)
{
// Do stuff...
}
}
Вместо того, чтобы оставлять эти установленные события открытыми, я думаю, что они должны активироваться какой-то логикой, но я не знаю, что это за логика. Может быть, их можно было активировать нажатием кнопки. Это позволило бы мне контролировать, когда инструкция передается по циклу. Теоретически я думаю, что это могло бы дать мне структуру конвейера. Может ли кто-нибудь внести свой вклад в это? Можно ли этого добиться с помощью только событий автоматического сброса?
Если вы посмотрите на первый блок кода, который я дал, вы увидите, что я пытался использовать блокировку, но это сделало так, что одновременно мог работать только один поток. Я хочу сделать так, чтобы он соответствовал формату Fetch0, {Decode0, Fetch1}, {Execute0, Decode1, Fetch3},...
и так далее. Нужны ли в этом случае замки?