Grrr... I spent a couple hours responding last night only to have IE eat my post when I previewed it.
You don't specify how you are using the abstraction layer, so I'll throw this out there in case you are doing something different.
Assuming your abstraction is an InstrumentController class, by far the easiest way to do what you want is to make an InstrumentSimulator class that is a child of the InstrumentController class. If your InstrumentController class includes a "Use Simulator" setting, back up and create a new class. Splitting up the functionality makes the code easier to understand and easier to test. InstrumentController is more reusable across different projects--if apps have different simulator requirements you're can create a project-specific InstrumentSimulator instead of modifying InstrumentController source code and potentially introducing bugs in other apps. Your main app needs almost no modifications to use the simulator. I use a conditional disable structure to switch between my real instrument drivers and my mock instrument drivers. No other changes needed.
Is there some reason simulator.vi should be write only instead of read-write?
The first question you need to answer is if you want your simulator data to be a global data ("static" data in other languages) available to all simulator instances or by-ref data unique for each simulator object. It's easier to get something that runs using global class data. It's not easier (imo) to get something that runs robustly using global class data. By-ref class data offers more flexibility in how you use the class. For example, using by-ref class data you can simulate n instruments (each with their own simulator vi) by simply dropping n class constants on the block diagram. You can't do that with global class data. You can also make a by-ref class behave like a global class by wrapping the by-ref object in another class as a global variable. If you start with a global class you can't make it behave like a by-ref class. It will always be a global class. My default is to use a by-ref class, especially if there's a chance you might reuse the class in other projects.
If you decide you want a global class:
Global variables - Easy for class users to use--no need to drag class wires around. Easy for class users to misuse if they are not aware of its global nature. Easy to implement getters and setters. Requires potentially complex semaphores if you have any read-modify-write operations. Allows concurrent access to different data elements.
Named Single Element Queue - Built in protection against race conditions. No concurrent access unless you implement a separate queue for each data element. Very slight possiblity of stepping on an identically named queue.
Functional Global - You can make a functional global behave more like a global variable or more like a named single element queue, depending on how you implement it. Personally I don't see a need for them in OOP.
If you decide you want a by-ref class:
Data Value Reference - Build in protection against race conditions. No concurrent access unless you implement a separate DVR for each data element.
Unnamed Single Element Queue - Pretty much the same as the DVR, except you have to manually implement a bit more of the functionality. Since the introduction of DVRs in 2009, I find the DVR a more natural device for storing shared data than the SEQ.
If you have a separate InstrumentSimulator class, what you're looking for is a class in which the methods run in the client's execution branch, *except* for Simulator.vi, which runs in a private, parallel execution branch. SciWare created an Active Object framework for by-ref classes that shows how to launch a class member vi in a parallel branch. (See LaunchProcess.vi.) You'd do that as part of InstrumentSimulator's initialization routine. Assuming Simulator.vi is just setters and getters, you can simplify his design a lot by removing the command queue and message queue. You'd also replace his Process.vi with your Simulator.vi.
Making InstrumentSimulator a global class avoids all the complexities required with making sure both branches have the same DVR or unnamed queue refnum. The data sharing is built into the global variable so you just have to launch Simulator.vi when the app starts.