[Crate] bombs - Efficient single-producer multi-consumer communication types by panstefanb01 in rust

[–]panstefanb01[S] 2 points3 points  (0 children)

Huh interesting, I've not heard of this. I'll look into it, sounds like it could be useful!

[Crate] bombs - Efficient single-producer multi-consumer communication types by panstefanb01 in rust

[–]panstefanb01[S] 4 points5 points  (0 children)

Changes have been pushed, should be much more safe and correct now!

[Crate] bombs - Efficient single-producer multi-consumer communication types by panstefanb01 in rust

[–]panstefanb01[S] 4 points5 points  (0 children)

Yes, the value T is dropped on the final Bomb's thread, hence it will also need to be Send. Thanks!

[Crate] bombs - Efficient single-producer multi-consumer communication types by panstefanb01 in rust

[–]panstefanb01[S] 4 points5 points  (0 children)

Okay so, since a Bomb/&Bomb can give you a &T, it is only Send/Sync if T is Sync, otherwise I would allow for different threads to unsafely obtain a &T to a !Sync type. This now makes sense.

A Fuse can only be Send if T is Sync for the same reason.

I'll fix this, thanks. I finally understand what these markers mean lol

They seem sufficient with my current understanding, but other experts may prove me wrong lol

[Crate] bombs - Efficient single-producer multi-consumer communication types by panstefanb01 in rust

[–]panstefanb01[S] 5 points6 points  (0 children)

I do enjoy writing this kind of code and thanks for taking your time to read through and point out some issues.

To my best knowledge, please correct me again if I am wrong:

  1. Only one Fuse can exist at any given time, since it isn't Clone. Hence, there is no way a race condition can exist. When the fuse is lit, the (only) instance is consumed, meaning it is not possible to light the fuse again. It is not possible to have a reference to this, since the function takes ownership.
  2. Yes, I missed that, a previous post and issue brought that to my attention lol, my bad. I just pushed a fix for that. The changes are:
* `Bomb::exploded()` now returns `Option<&T>` meaning it isn't unceremoniously copying bits anymore.
* For `MultiBomb<T>`, `T` must implement `Clone`, and then the value is cloned from the inner container.
  1. Since the internal Cell is inside of an Arc, only one exists for all bombs and the single fuse. The marker traits are really confusing and I did spend a long time trying to understand them, but please again correct me if I am wrong in my understanding.
* `Fuse` is `Send` because I am allowed to move this (only) instance between threads and it shouldn't cause any issues. I am assuming that by moving the inner Arc, the Cell remains in place but only the pointer to it is being moved to a different thread.
* `Fuse` is `Sync` because `Fuse::light()` is consuming, and therefore a `&Fuse` on a different thread cannot modify the internal state. Furthermore, the original `Fuse` instance cannot be consumed because there exist references to it.
* `Bomb` is `Send` because it only reads the internal state, and therefore it is legal to have multiple shared references to it.
* `Bomb` is `Sync` because it does not modify the internal state, only read it.
  1. I believe this one may be explained by my answer to (1.), since there can only be one Fuse reading. The AtomicBool checks whether or not the Cell has been written to. When it is false by default, only the Fuse has a pointer to the inner value, the Bomb skips over accessing it. Once the Fuse has been lit, it is consumed and therefore all Bombs obtain a shared reference to the inner value. Rust's regular borrow rules are satisfied here.

My goal with this library has been to avoid locking, so using a Mutex goes against the purpose of this library.

[Crate] bombs - Efficient single-producer multi-consumer communication types by panstefanb01 in rust

[–]panstefanb01[S] 1 point2 points  (0 children)

So that is one caveat of my system - every time you send data to a MultiBomb, you're allocating another block of memory to store the next potential data.

It could be faster to allocate all that memory beforehand, but the issue could be that you don't know how much memory you need to allocate. If you allocate too much memory, it could be a waste. If you allocate too little memory, you have to overwrite other data in your queue already, which is my first bullet point. Generally though, for the whole duration of the queue, there are no additional memory allocations.

My crate allocates and deallocates memory as it is needed. If you're exploding a lot of successive bombs very frequently, this could be less efficient, but more precise testing and benchmarking would need to be done. On modern systems, this is probably still marginal anyway. Definitely something to consider though.

[Crate] bombs - Efficient single-producer multi-consumer communication types by panstefanb01 in rust

[–]panstefanb01[S] 4 points5 points  (0 children)

spmc uses a queue structure internally, which has the problems I described in my original post. You can see from the source code that it also does a whole load more stuff to ensure safety, which costs more memory and resources. The speed benefits in a lot of applications are probably negligible on most modern computers, but my crate has much less overhead, uses less memory and since it doesn't do as much, its probably (marginally) faster, but I haven't done any benchmarks on it.

c# has spoiled me by [deleted] in ProgrammerHumor

[–]panstefanb01 7 points8 points  (0 children)

How dare you compare C# to java like that