How to run self method as Arc<RwLock<Self>>?

How to run self method as Arc<RwLock>? I want to create a run method that accepts N requests, and spawn a task to fullfill the task if it's not busy. I tried writing it into a single run method and it seems to work but I want to refactor it into a convenient method like process_job but couldn't figure how to do it.

Here, I'm spawning the task in run.

use std::{sync::Arc, time::Duration};

use tokio::{sync::RwLock, time::sleep};

struct Worker {
    busy: bool,
}

impl Worker {
    fn run(self) {
        let cloned = Arc::new(RwLock::new(self));
        // mimic accepting n jobs, practically this is from a rx channel.
        for _ in 0..10 {
            let cloned = cloned.clone();
            tokio::spawn(async move {
                let read_lock = cloned.read().await;
                if read_lock.busy {
                    println!("skip, job is busy");
                    return;
                }
                {
                    let mut write_lock = cloned.write().await;
                    write_lock.busy = true;
                }
                // mimic making progress
                for i in 0..100 {
                    sleep(Duration::from_millis(100)).await;
                }
                {
                    let mut write_lock = cloned.write().await;
                    write_lock.busy = false;
                }
            });
        }
    }
}

I want to somehow run it as a method but I'm getting the error:

  = note: type of `self` must be `Self` or a type that dereferences to it
   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
use std::{sync::Arc, time::Duration};

use tokio::{sync::RwLock, time::sleep};

struct Worker {
    busy: bool,
}

impl Worker {
    fn run(self) {
        let cloned = Arc::new(RwLock::new(self));
        // mimic accepting n jobs
        for _ in 0..10 {
            let cloned = cloned.clone();
            cloned.spawn_job();
        }
    }

    fn spawn_job(self: Arc<RwLock<Self>>) {
        let cloned = self.clone();
        tokio::spawn(async move {
            let read_lock = cloned.read().await;
            if read_lock.busy {
                println!("skip, job is busy");
                return;
            }
            {
                let mut write_lock = cloned.write().await;
                write_lock.busy = true;
            }
            // mimic making progress
            for i in 0..100 {
                sleep(Duration::from_millis(100)).await;
            }
            {
                let mut write_lock = cloned.write().await;
                write_lock.busy = false;
            }
        });
    }
}

Thanks for the help.

The error message is crystal clear, isn't it? You are not allowed to have arbitrary types for self, only the ones enumerated in the message. So you'll have to write an associated function, not a method.


However, there's a way more serious problem. Arc inherently prevents unique ownership, so you won't be able to call any methods that require transferring ownership of self if your data is behind an Arc.

You could make it a trait method.

trait Spawn {
    fn spawn_job(self);
}

impl Spawn for Arc<RwLock<Worker>> {
    fn spawn_job(self) {
        // ...
    }
}

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.