当前位置: 动力学知识库 > 问答 > 编程问答 >

Advice on Multithreading an emulator in C#. Pattern/Concepts

问题描述:

I'm working on a MIPS Emulator as a learning project. In order to get the desired performance I would like to have each processor always sleep in their own thread and when a DMA transfer occurs they start processing.

I've used the BackgroundWorker before and have just started using the async/away instructions and I've read about Thread Pooling. The "memory space" would be shared so the DMA status bits are the "natural" locking mechanism. These threading techniques don't seem to do what I would like. What am I missing?

Maybe this code example (Compiles, doesn't function) will explain what I'm thinking.

public class ThreadingEmulatorCode

{

static Memory memory = new Memory();

public ThreadingEmulatorCode()

{

CPU cpu = new CPU();

memory.OnDMAZero += cpu.zero.Execute(new DMAEventArgs());

memory.OnDMAOne += cpu.one.Execute(new DMAEventArgs());

cpu.Run(ref memory);

}

}

public delegate void dmazero(DMAEventArgs args);

public delegate void dmaone(DMAEventArgs args);

public class DMAEventArgs : EventArgs

{

public byte[] Data { get; set; }

public uint Address { get; set; }

}

public class Memory

{

public event dmazero OnDMAZero;

public event dmaone OnDMAOne;

private const uint CoprocZeroDMA = 0x1FC00000;

private const uint CoprocOneDMA = 0xBFC00000;

private byte[] memory;

public Memory()

{

this.memory = new byte[(8 * 1024 * 1024)];

}

public byte this[uint address]

{

get

{

return memory[address];

}

set

{

memory[address] = value;

if (address == CoprocZeroDMA && OnDMAZero != null)

OnDMAZero(new DMAEventArgs());

if (address == CoprocOneDMA && OnDMAOne != null)

OnDMAOne(new DMAEventArgs());

}

}

}

public class CPU

{

public CoprocZero zero;

public CoprocOne one;

public void Run(ref Memory memory)

{

/* Start Executing Instructions */

}

public CPU()

{

zero = new CoprocZero();

one = new CoprocOne();

}

}

public class CoprocZero

{

public CoprocZero(/* Start Listening Thread */) { }

public dmazero Execute(DMAEventArgs dmaEvent)

{

/* Process DMA'd Data */

throw new NotImplementedException();

}

}

public class CoprocOne

{

public CoprocOne(/* Start Listening Thread */) { }

public dmaone Execute(DMAEventArgs dmaEvent)

{

/* Process DMA'd Data */

throw new NotImplementedException();

}

}

Ideas or suggestions? Thanks.

网友答案:

Looks like I just needed to spend some more time with the code. Sorry. I originally expected that the tight while on TryPeek would max CPU, but it sits at Zero CPU in the Process List. I haven't verified total performance yet, but I think this will work.

// Code to Test
// ThreadingExampleCode stackOverflow = new ThreadingExampleCode();
// Thread.Sleep(new TimeSpan(1, 0, 0));
public class ThreadingExampleCode
{
    public static Memory memory;
    private CoprocZero zero;
    private CoprocOne one;
    private CPU cpu;
    private Thread coprocZero;
    private Thread coprocOne;
    ConcurrentQueue<uint> coprocZeroQueue = new ConcurrentQueue<uint>();
    ConcurrentQueue<uint> coprocOneQueue = new ConcurrentQueue<uint>();

    public ThreadingExampleCode()
    {
        memory = new Memory();
        memory.OnDMAZero += MemoryOnOnDmaZero;
        memory.OnDMAOne += MemoryOnOnDmaOne;

        cpu = new CPU(memory);
        zero = new CoprocZero(memory, coprocZeroQueue);
        one = new CoprocOne(memory, coprocOneQueue);
        coprocZero = new Thread(zero.RunParm);
        coprocZero.Start();

        coprocOne = new Thread(one.RunParm);
        coprocOne.Start();

        cpu.Run();
    }

    private void MemoryOnOnDmaOne(DMAEventArgs args)
    {
        coprocOneQueue.Enqueue(args.Address);
    }

    private void MemoryOnOnDmaZero(DMAEventArgs args)
    {
        coprocZeroQueue.Enqueue(args.Address);
    }
}

public delegate void dmazero(DMAEventArgs args);

public delegate void dmaone(DMAEventArgs args);

public class DMAEventArgs : EventArgs
{
    public uint Address { get; set; }
}

public class Memory
{
    public event dmazero OnDMAZero;
    public event dmaone OnDMAOne;

    public const uint CoprocZeroDMA = 1 * 1024 * 1024;
    public const uint CoprocOneDMA = 2 * 1024 * 1024;
    private byte[] memory;

    public Memory()
    {
        this.memory = new byte[(8 * 1024 * 1024)];
    }

    public byte this[uint address]
    {
        get { return memory[address]; }
        set
        {
            memory[address] = value;
            if (address == CoprocZeroDMA && OnDMAZero != null)
                OnDMAZero(new DMAEventArgs());
            if (address == CoprocOneDMA && OnDMAOne != null)
                OnDMAOne(new DMAEventArgs());
        }
    }
}

public class CPU
{
    private Memory memory;
    public CPU(Memory inMemory)
    {
        memory = inMemory;
    }

    public void Run()
    {
        /* Start Executing Instructions */
        memory[Memory.CoprocZeroDMA] = 0x01;
        memory[Memory.CoprocOneDMA] = 0x01;
    }
}

public class CoprocZero
{
    private ConcurrentQueue<uint> queueToMonitor;
    private Memory memory;
    public CoprocZero(Memory inMemory, ConcurrentQueue<uint> queue)
    {
        memory = inMemory;
        queueToMonitor = queue;
    }

    public void RunParm()
    {
        uint memoryAddress;
        while (!queueToMonitor.TryPeek(out memoryAddress)) { };

        if (queueToMonitor.TryDequeue(out memoryAddress))
        {
            Debugger.Break();
        }
    }
}

public class CoprocOne
{
    private Memory memory;
    private ConcurrentQueue<uint> queueToMonitor;
    public CoprocOne(Memory inMemory, ConcurrentQueue<uint> queue)
    {
        memory = inMemory;
        queueToMonitor = queue;
    }

    public void RunParm()
    {
        uint memoryAddress;
        while (!queueToMonitor.TryPeek(out memoryAddress)) { };

        if (queueToMonitor.TryDequeue(out memoryAddress))
        {
            Debugger.Break();
        }
    }
}
分享给朋友:
您可能感兴趣的文章:
随机阅读: