-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
More beginner friendly tutorial? #29
Comments
After some reflection, I realized a way you could use In the timer example, the timer chip could have an FnOnce which calls a motherboard's function However I recognize a problem with this design: It requires the motherboard's functions to be defined consistently. Just like I want the chips to be replaceable, I want the Motherboard to be replaceable too. Not all messages need to be read. Some motherboards will route the timer chip. Some won't. I can't think of a way to handle this situation with FnOnce. I might be forced to revert to using enum. |
The approach used by Stakker is instead of having enums to express the messages, the messages are actually just methods on the actor structure. So instead of having Msg::GetMemoryByte, you'd have I think it is okay to hard-code the method names, since you are also hard-coding the enum names -- so it is about the same. If you need to switch out the Motherboard, you could do that with compile-time However if you really don't want everything fixed at compile-time (e.g. if you want to switch between different motherboards at runtime rather than compile-time), then you could do it all with The business with FnOnce is that all messages are handled with FnOnce internally, but in user code, it looks like function calls on the destination object (although with slightly different syntax and wrapped in a macro like Let me know if this makes sense. I'm happy to answer more questions. |
Thank you for your response. After much thought, and testing with your examples, I am going ahead and rebuilding my emulator to use your framework. |
Do you have any suggestions how to best declare actors which have a circular reference? For example, the Motherboard saves a reference to all of the chips, but all of the chips also have a reference to the motherboard. If I declare all of the chips first, then I might have to have an Optional field in all of the chips for the motherboard originally set to |
This can be done using I'm just about to travel away for a couple of days. I'll be back online on Sunday if you have any more questions. |
Thank you very much, and please don't feel obliged to answer my questions quickly! |
I have never used an "Actor Model" before, and so I am new to this form of design...
I have been designing something in Rust, but I keep on hitting up against the Rust borrow checker.
Your crate looks promising, but confusing, so I hope maybe I can use what you have built.
I am sorry, I don't know a better way to reach you other than via this "Issues" section. I hope this is okay.
I have been building an emulator. The emulator consists of multiple emulated chips which need to communicate with each-other.
Ordinarily emulators' components are written in a tightly coupled form, where one chip would have a direct reference to another chip. However, I want to retain the ability for each chip to work independently of the others.
When it wants to interact with another chip, it should send a message to the motherboard. And the motherboard should route the message to the appropriate location.
The benefit of this design is the modularity / flexibility, being able to simulate a real computer. For example, the motherboard manufacturers might have chosen to leave some of the chip's pins disconnected. The chip is unaware of the lacking pin connections, and it will attempt to send out a message. The motherboard would take care of this lacking routing. The chip could continue to work as it was intended, regardless of how everything else connects to it. I would like to build this emulation.
At first, I built this emulator with all chips in separate threads using channel message passing.
This worked up to a point. The problem is that these emulated chips run at a fairly high speed with only 200 nanoseconds to spare.
After some testing, I realized that multithreading is not the solution. Simply sending a message and blocking on a reply took over 500 nanoseconds.
I realized I need to rewrite the emulator to run single threaded without channels. However, pretty quickly I ran into issues with the borrow checker. With all of the chips referencing the motherboard, and the motherboard referencing all of the chips back, I kept running into circular reference problems. No matter what I tried, the borrow checker kept being angry at me.
Finally, I found out about RefCell... which I want to avoid... It would be better if all references are checked at compile time.
That is how I discovered your
stakker
andqcell
crates.Considering that I am looking for all of these chips to communicate with each other through messages and be run at specific intervals, your
stakker
crate seems like a good fit for my use-case. However, I am quite confused how to use it. It has multiple functions and macros which I am not used to.Reading though your guide, I see that all messages are
FnOnce
.. I am especially confused about this.Currently I have a large set of Enums designating each message. Each chip has the ability to process the message by matching on the enum values and doing a certain behavior.
For example, the CPU chip can have an enum message
Msg::GetMemoryByte(addr, &mut byte)
This message gets routed by the motherboard to the Memory chip. The memory chip reads the enum and sets the mutable byte.
When the memory chip is done, the CPU chip gets another enum message that the byte has been set.
Another example: the Timer chip has finished ticking and now wants to alert that time has elapsed. It sends out a message
Msg::TimerElapsed{timer_id: 2}
. The motherboard sees this message. Ordinarily, it would route it to the CPU, however the manufacturers decided to only connect timer_id 1 to the CPU. timer_id 2 is left disconnected. So, the message will be dropped.This is how the chips communicate, independent of each other.
Reading through your guide, I feel as if my enum solution is somewhat inefficient, and your FnOnce solution should be much better. However I continue to be quite confused, how to use it. Would you be able to tell me how my above examples could be reformatted to use FnOnce instead?
Thank you for your time.
The text was updated successfully, but these errors were encountered: