4 ms·
I used the system you are advocating in my utility at first. The problem is that you need to constantly check for work. That is expensive on tight loops. Yes,
by gavinhoward 3y ago
I used the system you are advocating in my utility at first.
The problem is that you need to constantly check for work. That is expensive on tight loops. Yes, I checked on every loop iteration unless I knew a small, but constant, amount of work had to be done.
That's the thing: if you have a tight loop, do you know how long it's going to take to run through everything? In addition, when a SIGINT comes, can you be sure that your state is correct?
Here's a test: download my utility and run these commands:
$ git checkout 2.7.0
$ ./configure.sh -gO3
$ make
$ echo "2^2^32" | bin/bc
Then send a SIGINT after a random amount of time.
I did that twice, and both times, I triggered asserts. Some state was wrong.
This was after I had carefully gone through the entire codebase to check signals everywhere.
Now do this:
$ git checkout 6.7.0
$ ./configure.sh -gO3 -Sbc.sigint.reset
$ make
$ echo "2^2^32" | bin/bc
And send a SIGINT after a random amount of time.
bc exits because its stdin is a pipe, but nothing goes wrong. If you do it like this:
$ bin/bc
>>> 2^2^32
^C
interrupt (type "quit" to exit)
0: (main)
ready for more input
>>>
And you can merrily continue.
Semaphores and mutexes have the same problem: I would need to keep checking them.
I understand why you think the way you do; I did too. But the real world is more complicated.
- aa-jv 3y agoIn the 'real world' compare-and-swap operations (such as one would find in atomic types used for communication between worker and handler) are single-cycle operations, if not a hard CPU flag... >I understand why you think the way you do; I did too. But the real world is more complicated. Please consider the complications of the high-end audio world, where such techniques are well established. Not only must bat-out-of-hell threads have all the gumption they can muster, but they have to be able to be controlled - in as close to realtime as possible - by outside handler threads. I think boffinaudio is trying to help you improve your code quality. Its not bad advice to re-think this.
- deleted 3y ago[deleted]
- gavinhoward 3y agoI've done real-time too. If I was in that context, yes, I would use outside handler threads, but that's because I could probably put the compare-and-swap in one place (or very few). As of 2.7.0, my bc had 77 places where signals were checked, and I was probably missing a few. Real-time is different from what I was doing, so it required different techniques.
- helpfulContrib 3y ago>I've done real-time too. There is a case for signals in strictly real-time, strictly high-performance, and also strictly realtime+high-performance code. You have decided to go strictly for high-performance, for your well-argued reasons, and you've abandoned a standard practice for your stated claims, but this isn't just about your code - its about how people can mis-use signals, and in your case you're mis-using signals by not using them. It is the advice: >"Yes be very afraid of signals." .. which feels not entirely appropriate. So I took a look at the bc code, and I too am terrified of your use of longjmp. It appears to me you've gotten somewhat smelly code because you didn't find the appropriate datatype for your case, and decided to roll your own scheduling instead. Ouch. >As of 2.7.0, my bc had 77 places where signals were checked, and I was probably missing a few. To refactor this to a simple CAS operation to see if the thread should terminate, doesn't seem too unrealistic to me. Only 77 places to drop a macro that does the op - checking only if the signal handler has told your high-performance thread us to stop, hup, die, etc. Signals are awesome, and work great - obviously - for many, many high-performance applications, and your high-performance, CPU-bound application might feel like the only way you could do it - but you certainly can attain the same performance and still handle signals like a well-behaved application that doesn't have to take big leaps just to stay ahead of the scheduler ..
- gavinhoward 3y agoMy 77 uses were macros that did atomically check a flag. My point was that that does not scale. Also, I didn't have a scheduler. The point of interrupts is that you don't need a scheduler.
- 3y ago
- epcoa 3y agoSorry but both boffinAudio and you are providing considerable misinformation. https://stackoverflow.com/questions/5339769/relative-performance-of-swap-vs-compare-and-swap-locks-on-x86 https://stackoverflow.com/questions/5339769/relative-perform... Bus activity makes CAS and any atomic operation far more costly than a single cycle. If they were really that cheap then every operation would just be atomic. In general you must trade off bandwidth for improved latency. Audio work by its nature can and must do this. It is not the appropriate trade off in frankly most cases of computing (even if it is arguably more interesting)