3 ms·
I designed a syntax for this: that everything is a state machine progression, a bit like sequence types in the article. state1a state1b state1c | state2a st
by samsquire 3y ago
I designed a syntax for this: that everything is a state machine progression, a bit like sequence types in the article.
state1a state1b state1c | state2a state2b state2c | state3a state3b state3c
This means wait for state1a, state1b state1c in any order, then move to the next sequence of things to wait for.
In a multithreaded server or multimachine distributed system, there are global states you want to wait for and then trigger behaviour. The communication can be inferred and optimised and scheduled.
It's BNF syntax - inspired by parsing technology for parsing sequences of tokens but tokens represent events.
If you use printf debugging a lot, you know the progression of what you see is what happened and that helps you understand what went wrong. So why not write or generate the log of sequence of actions you want directly not worry about details?
But wait! There's more. You can define movements between things.
So take an async/await thread pool, this syntax defines an async/await thread pool:
next_free_thread(thread:2);
task(task:A) thread(thread:1) assignment(task:A, thread:1) = running_on(task:A, thread:1) | paused(task:A, thread:1);
running_on(task:A, thread:1)
thread(thread:1)
assignment(task:A, thread:1)
thread_free(thread:next_free_thread) = fork(task:A, task:B)
| send_task_to_thread(task:B, thread:next_free_thread)
| running_on(task:B, thread:2)
paused(task:A, thread:1)
running_on(task:A, thread:1)
assignment(task:B, thread:2)
| { yield(task:B, returnvalue) | paused(task:B, thread:2) }
{ await(task:A, task:B, returnvalue) | paused(task:A, thread:1) }
| send_returnvalue(task:B, task:A, returnvalue);
Why not just write what you want to happen and then the computer works out how to schedule it and parallelize it?
I think iteration/looping and state persistence and closures are all related.
I have a parser for this syntax and a multithreaded barrier runtime which I'm working on, I use liburing. I want to get to 500 million requests per second of the and ~50ish nanosecond latency of LMAX Disruptor.
The notation could be used for business programming and low level server programming I think.
- 082349872349872 3y ago> wait for state1a, state1b state1c in any order Conway worked out some results for non-serialised (commutative) events in Regular Algebra and Finite Machines about half a century ago.
- kitd 3y agoThis looks like it could be modelled by a petri net. Your states are typed tokens, and tasks (ie transitions) are triggered by the presence of tokens and produce tokens as output. IMHO petri nets are the most widely applicable method for modelling concurrent processes that I've seen yet.
- samsquire 3y agoI've read casually around petri nets and graphical diagrams. I would love to talk more about this. Would you like to talk more about this subject?
- vardump 3y agoMight be useful in OS kernel programming, when threads are not available. Like in IRQs, etc. My state machines in those contexts are such beasts sometimes, when you have to account for different combinations of DMA progress/completion, etc. Sometimes the hardware limitations you need to handle in software makes you really bang your head to the wall...
- touisteur 3y agoThread-per-core architectures might bring this back to the fore. Especially with things like GPUDirect, StorageDirect and all the DMA engines being slowly integrated into everything. If you have some taskgraph that is static or predictible (think closed-loop control) and you need low latency this might be your best option.
- samsquire 3y agoWould love to talk to you more about this, do you have an email address I can get to you at?
- mikhailfranco 3y agoI think joearms laid out the rough spec for this in UBF(c): https://ubf.github.io/ubf/ubf-user-guide.en.html https://ubf.github.io/ubf/ubf-user-guide.en.html but part (c) was only ever a sketch of a service/event grammar. I implemented REGEV (regular expression for events) in my previous job. It was a REGEX for event types, but in that case, applied to log/trace emissions from test runs. So it allowed you to specify a regex of what events to expect for success, and had various listening and pattern-matching streams for runtime verification. It did not generate full-blown state machines for every protocol grammar. The wildcard matching helped ensure the tests were not fragile to minor changes to the code, or extra trace/log emissions. So I think the opposite (complement) of what you were describing - not a specification of what should happen, but a grammar pattern to match downstream of what actually happened. P.S. It's closed source, but the company is bankrupt, so maybe the IP will surface some day.
- samsquire 3y agoWould love to talk more about this with you, do you have an email address I can email you with? Did you regex engine support commutative events? (Happen in either order?)