Add a semaphore to limit the number of threads downloading avatars
This commit is contained in:
parent
b3cbdd4d99
commit
34883301f2
5 changed files with 35 additions and 6 deletions
|
@ -1,6 +1,6 @@
|
|||
extern crate url;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Mutex, Condvar};
|
||||
use std::thread;
|
||||
use self::url::Url;
|
||||
use std::sync::mpsc::{Sender, Receiver};
|
||||
|
@ -45,6 +45,7 @@ impl Backend {
|
|||
internal_tx: None,
|
||||
data: Arc::new(Mutex::new(data)),
|
||||
user_info_cache: CacheMap::new().timeout(60*60),
|
||||
limit_threads: Arc::new((Mutex::new(0u8), Condvar::new())),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::{Arc, Mutex, Condvar};
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use error::Error;
|
||||
|
@ -133,6 +133,8 @@ pub struct Backend {
|
|||
|
||||
// user info cache, uid -> (name, avatar)
|
||||
pub user_info_cache: CacheMap<Arc<Mutex<(String, String)>>>,
|
||||
// semaphore to limit the number of threads downloading images
|
||||
pub limit_threads: Arc<(Mutex<u8>, Condvar)>,
|
||||
}
|
||||
|
||||
impl Clone for Backend {
|
||||
|
@ -142,6 +144,7 @@ impl Clone for Backend {
|
|||
data: self.data.clone(),
|
||||
internal_tx: self.internal_tx.clone(),
|
||||
user_info_cache: self.user_info_cache.clone(),
|
||||
limit_threads: self.limit_threads.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,7 +101,21 @@ pub fn get_avatar_async(bk: &Backend, member: Option<Member>, tx: Sender<String>
|
|||
let alias = m.get_alias().clone();
|
||||
let avatar = m.avatar.clone();
|
||||
|
||||
let thread_count = bk.limit_threads.clone();
|
||||
thread::spawn(move || {
|
||||
// waiting, less than 20 threads at the same time
|
||||
// this is a semaphore
|
||||
// TODO: use std::sync::Semaphore when it's on stable version
|
||||
// https://doc.rust-lang.org/1.1.0/std/sync/struct.Semaphore.html
|
||||
let &(ref num, ref cvar) = &*thread_count;
|
||||
{
|
||||
let mut start = num.lock().unwrap();
|
||||
while *start >= 20 {
|
||||
start = cvar.wait(start).unwrap()
|
||||
}
|
||||
*start += 1;
|
||||
}
|
||||
|
||||
match get_user_avatar_img(&baseu, uid, alias.unwrap_or_default(), avatar.unwrap_or_default()) {
|
||||
Ok(fname) => {
|
||||
tx.send(fname.clone()).unwrap();
|
||||
|
@ -110,6 +124,13 @@ pub fn get_avatar_async(bk: &Backend, member: Option<Member>, tx: Sender<String>
|
|||
tx.send(String::new()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
// freeing the cvar for new threads
|
||||
{
|
||||
let mut counter = num.lock().unwrap();
|
||||
*counter -= 1;
|
||||
}
|
||||
cvar.notify_one();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -36,7 +36,7 @@ impl<'a> MemberBox<'a> {
|
|||
username.set_text(&self.member.get_alias().unwrap_or_default());
|
||||
|
||||
let avatar = gtk::Image::new_from_icon_name("avatar-default-symbolic", 3);
|
||||
get_member_avatar(backend.clone(), avatar.clone(), Some(self.member.clone()), 30);
|
||||
get_member_avatar(backend.clone(), avatar.clone(), Some(self.member.clone()), 30, 3);
|
||||
avatar.set_alignment(0.5, 0.);
|
||||
|
||||
w.pack_start(&avatar, false, false, 5);
|
||||
|
@ -48,7 +48,11 @@ impl<'a> MemberBox<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_member_avatar(backend: Sender<BKCommand>, img: gtk::Image, m: Option<Member>, size: i32) {
|
||||
pub fn get_member_avatar(backend: Sender<BKCommand>, img: gtk::Image, m: Option<Member>, size: i32, tries: i32) {
|
||||
if tries <= 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let (tx, rx): (Sender<String>, Receiver<String>) = channel();
|
||||
backend.send(BKCommand::GetAvatarAsync(m.clone(), tx)).unwrap();
|
||||
gtk::timeout_add(50, move || match rx.try_recv() {
|
||||
|
@ -59,7 +63,7 @@ pub fn get_member_avatar(backend: Sender<BKCommand>, img: gtk::Image, m: Option<
|
|||
} else {
|
||||
// trying again if fail
|
||||
img.set_from_icon_name("avatar-default-symbolic", 5);
|
||||
get_member_avatar(backend.clone(), img.clone(), m.clone(), size);
|
||||
get_member_avatar(backend.clone(), img.clone(), m.clone(), size, tries - 1);
|
||||
}
|
||||
|
||||
gtk::Continue(false)
|
||||
|
|
|
@ -127,7 +127,7 @@ impl<'a> MessageBox<'a> {
|
|||
avatar = gtk::Image::new_from_icon_name("avatar-default-symbolic", 5);
|
||||
}
|
||||
|
||||
get_member_avatar(backend.clone(), avatar.clone(), m.cloned(), 40);
|
||||
get_member_avatar(backend.clone(), avatar.clone(), m.cloned(), 40, 3);
|
||||
avatar.set_alignment(0.5, 0.);
|
||||
|
||||
avatar
|
||||
|
|
Loading…
Reference in a new issue