Module with own thread and accessed by multiple threads

Hello,

I want to implement the following:

  • have a module that starts and run a cyclic internal thread and works every cycle on the module internal data (a vector)
  • have functions implemented in the module that can be called from other threads and also modify the module internal data structure. E.g. add data to the vector

I found many examples but they always show only code directly running in main. I cannot figure out how to put things together in a separate module.

I think I need a lock that ensures that only one thread works on the data at a time.

  • initialise the lock when the module gets created
  • get lock in every function before accessing data of the module
  • getting the lock in the cyclic thread before modifying the data

Is this correct?

Is there a simple example how to implement something like this?

Normally I would do this with an instance of a struct. Wrap the collection/vec in a mutex and put that in the struct. Launch the thread when the instance of the struct is created, and you might also want to keep the join handle for the thread in the struct as well if you want to do a clean shutdown of the thread when the struct instance is dropped.

Then you can make Impl functions to manipulate the data held in the mutex.

Here's a partial example:

And, of course, you can put the implementation of the struct in a separate module if you want.

2 Likes

The ability to put functions in a module doesn't depend on what they do. Modules are a fundamental abstraction – they organize code syntactically, the don't do anything actively (at runtime). You don't need to do anything special in order to be able to put a function in a module – you can do this freely, with any function and any module you create.

Thank you for this example. I managed to crate a working sample based on it.

One additional question. If I want to protect the complete MyThing in Arc.
Would I do it the same way?

Peter

Naw. With the description you've provided I usually go with a work queue. The internal thread would be the only thing accessing the vector.

@Coding-Badly is probably right, if you're just using the vec to add data for the thread to process. (From your initial description it's not too clear what you want to do in the thread).

But if that's the case, then you might consider something like a crossbeam channel, which is just a thread-protected queue. Then you can just give the receiver-side to the thread and make clones of the sender-side to give to all the other threads that want to send it data. You wouldn't need the vec, the mutex, or maybe even the struct, and the thread could automatically shut down when all the transmitters disappear - so no separate quit signaling required.

But to answer you next question, yes you can wrap a MyThing in an Arc. If you know you need one, you can just have new() return that instead:

    pub fn new() -> Arc<Self> {
        let data = Arc::new(Mutex::new(vec![]));
        let thr_data = data.clone();
        let thr = thread::spawn(move || Self::thread_func(thr_data));
        Arc::new(Self { data, thr })
    }
1 Like