sciter-sdk / rust-sciter

Rust bindings for Sciter
https://sciter.com
MIT License
804 stars 76 forks source link

Multiple thread support #16

Open harryfei opened 7 years ago

harryfei commented 7 years ago

I think the native sciter sdk(c++ library) is multiple thread friendly. However, it sucks when I use this rust binding in a multiple thead situation.
Currently both sciter::Window and sciter::Host are not Sync or Send. Do you have any plan to change this?

pravic commented 7 years ago

Haven't tried it yet. Sciter has become thread-safe not so long ago (since 3.3.1.9) and had issues at the beginning with it.

Okay, I will take a look. Or you can make a PR with corresponding improvements and examples.

harryfei commented 7 years ago

I will try. :smile:

WLBF commented 6 years ago

I hope make sciter::Element multi thread friendly first, using working thread update dom is very common way to avoid blocking ui thread.

pravic commented 6 years ago

Partly true, because UI thread can be blocked by Sciter itself (that's how thread safe API calls are implemented). But not always, of course.

As for Send+Sync candidates - it is sciter::Element and sciter::Value.

WLBF commented 6 years ago
macro_rules! MAKE_HANDLE {
    ($name:ident, $inner:ident) => {
        #[repr(C)]
        pub struct $inner { _unused: usize }
        pub type $name = *mut $inner;
    };
}
...
MAKE_HANDLE!(HELEMENT, _HELEMENT);
...
pub struct Element {
    he: HELEMENT,
}

It seems like HELEMENT is a raw pointer comes from sciter.dll and all Element api pass it back to sciter.dll. I think since sciter is thread-safe, send or sync Element between threads should also be fine.

pravic commented 6 years ago

There we go: #18 for the Element.

pravic commented 6 years ago

And for the Value. However, Value API is not thread safe, so it can be marked as Send only, but not as Sync.

Since 0.4.21 version.

pravic commented 6 years ago

Hmm. You should isolate value received from UI before passing it to another thread.

I am not sure how to make this guarantee in Rust. May be via some handle/wrapper, which is Send-able and which calls ValueIsolate for its underlaying value.

pravic commented 6 years ago

sciter::SafeValue? :)

pravic commented 6 years ago

May be via some handle/wrapper

This. Also it comes with Deref, so it's quite easy to use:

let v = Value::map();

let mut v = v.isolate();
std::thread::spawn(move || {
  v.set_item("five", 5);
  println!("{:?}", *v);
});
pravic commented 6 years ago

It's not so easy. It is messy, actually.

Part of the Value API is thread safe (e.g. function calls), the rest of it is not (e.g. map/array access).

Moreover, a Value can hold a reference to a DOM resource which must be accessed only from the GUI thread.

And the last: arrays and maps from script come as Object/Array and Object/Object types, so you can't distinguish them from class instances. And you must isolate them if you want to store or pass between threads.

Need to think.

gaoqiangz commented 2 years ago
impl Value {
    fn to_function(&self) -> Option<Function> {
        //check type...
        Some(Function { ... })
    }
}

struct Function {
    raw: Value
}

impl Function {
    fn call(&self,...) -> Result<...> {
        ...
    }
}

// function call is thread safe
unsafe impl Send for Function {}
unsafe impl Sync for Function {}

Is this a solution?

Moreover, a Value can hold a reference to a DOM resource which must be accessed only from the GUI thread.

As you say, sciter::Value also shouldn't be Send.

pravic commented 2 years ago

You see, some values can be sent to another thread, some - don't:

So, some sciter::Value can be sent, other - need isolate. But isolate converts the value to plain JSON, so it's not an option to isolate everything.

I think, the only options is to have an ability to mark an intention to send a value (isolated or not). Some kind of an unsafe wrapper.