Looking for a specific concurent datastructure

Hey!

I'm writing a simple renderer for my game (I'm not using an engine). The whole update logic takes place on the main thread, while the rendering logic (and some other related calculations) are done on a separate thread. The main thread is supposed to periodically send data to the render thread. This way, the render thread can render a frame while the main thread starts computing the next one.

Currently, I'm using a channel from the standard library. The main thread simply sends data through that channel and the render threads waits on it everytime it wants to render a new frame. I want to optimize this process.

The idea

  • Use two RenderData instances (probably allocated on the heap). While the main thread can access the first instance, the render thread can access the other one. Always using the same two instances allows reusing buffer allocations.
  • When a thread finishes its work, it indicates to the system it is ready and starts blocking.
  • Once the other thread finishes its work, it indicates to the system it is ready.
  • Both threads swap the pointer to RenderData they are using with the other.

Before a thread sets itself as finished, it has exclusive access to its own RenderData instance.

Here is a pseudo-implementation of what I'm talking about, so that you can understand better how I want it to work.

struct Shared<T> {
    a: UnsafeCell<T>,
    b: UnsafeCell<T>,
}

struct Swap<T> {
    shared: *mut Shared<T>,
    value: *mut T,
}

impl<T> Swap<T> {
     fn wait_and_swap(this: &mut Self) {
        // block until the other thread is ready.

        if this.value == this.shared.a.get() {
            this.value = this.shared.b.get();
        } else {
            this.value = this.shared.a.get();
        }
        // I don't think we need to wait on the other thread
        // because the `wait_and_swap` function won't return
        // until pointers are swapped anyway.
    }
}

impl Deref for Swap<T> {}
impl DerefMut for Swap<T> {}

Actual questions

Is this actually a good idea? I added a lot of context because I want to avoid the x-y problem, so if you have a better idea, please share it!

First, is there a crate that does this or something close enough?

If not, is there a way to correctly do this using simple syncronisation primitives? The part I'm struggling with is the "both threads needs to wait for one another". It's like a mutex lock, but the first thread locks and the second thread unlocks. How error prone would it be to implement it myself? Is there useful resources on the subject?

1 Like

Just pass the owned T values (probably wrapped in a box). Back and forth between the two threads. You could just use two channels between them.

Or you have some kind of swap struct that holds two Option<Box under a mutex, and condvar. When A thread completes it stores its Box in the slot for the other thread and checks it's slot is set if not it waits for the condvar, else it signals the other thread and grabs it's data. I'm a bit too busy to write an example right now (I'm assuming you've used condvars before), but it's far easier than using unsafe correctly.

bounded channels of length zero:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.