Call on specific thread

Having problems with building or using the CefGlue .NET/Mono binding? Ask your questions here.

Moderator: fddima

Call on specific thread

Postby teremy » Sun Aug 28, 2016 9:20 pm

Hello.
Let me first explain this shortly, if the following is too long to read:
When I am currently in the renderer thread, how can I call something that is not meant for the renderer thread ( resulting in the window becoming white and not doing anything )?

I am experimenting with the cefglue demo project. I am using the gtk sharp project ( and the demo project that is used by all the different demo projects that vary on the gui toolkit ).

I spend quite some time to understand the architecture of chromium/the demo project.
For testing purpose I want to move the window to a different location ( or top left for starters ). This can be done with Move(0, 0). I added a static reference to itself in MainViewImpl. So I can access it anywhere with MainViewImpl.instance.
If I call this in the render process, the browser window will become white and nothing will happen.

PostTask can be used to call something on another thread, right?
Another option is to send messages to another thread, right?

I tried using PostTask but it didn't work. The only thing where it is actually executed ( but resulting in the browser window becoming white... ) is the renderer thread: CefThreadId.Renderer.
I tried a static method as a parameter but also with lambda expression ( so I can create a function on the fly ) like this:

Code: Select all
DemoApp.PostTask(CefThreadId.UI, () => {  MainViewImpl.instance.Move(0, 0); });


Another question: The gtk stuff is not running on a cef thread, right? CefTaskRunner.GetForCurrentThread() returns an empty reference in the constructor of MainViewImpl.cs. How can I run things on this (main) thread? With my own loop and a Queue<Action> maybe? So I add something to the queue in the renderer and the main thread sees that the queue isn't empty, so it dequeues the element and invokes it.
teremy
Techie
 
Posts: 15
Joined: Mon Aug 22, 2016 8:51 am

Re: Call on specific thread

Postby fddima » Mon Aug 29, 2016 9:22 am

Hello.

CefGlue's demo app is may be more complex to be a sample.

First thing that you interested in is CEF wiki https://bitbucket.org/chromiumembedded/cef/wiki/Home (read articles mostly about usage), and more important https://bitbucket.org/chromiumembedded/ ... alUsage.md .

For threading:

1. Regardless to how it is done in demo app, it is better to use CefRuntime.RunMessageLoop instead of external message loops. This provides best performance and works correctly in Win32 environments (it almost fine work with WinForms). For GTK# - don't use it, if you not ready to hack it.

2. CEF has own threads which available with CEF-related calls (i.e. PostTask). On windows you can use multi-threaded message loop, in that case CEF creates separate UI thread, and in this case CEF UI thread and Main UI thread is different. This is allow integrate CEF in cases when you not own message loop.

3. New CEF versions contains integration with external message loops by using single thread (ExternalMessagePump option). I'm personally not use this, but can be helpful for integrating in GTK, WPF and other UI frameworks.

So CEF provides lot of options, i'm recommend choose simplest and try with it. Or if you have specific task - then may be you can ask more directed questions, it is hard to explain everything in short.

Regarding to PostTask - it work, but CEF provides only post action. Send (in terms of win32) is not provided. To posting tasks on non-CEF threads you should use correlated native's. I mean Task.Run, Control.Invoke and others.

So:

DemoApp.PostTask(CefThreadId.UI, () => { MainViewImpl.instance.Move(0, 0); });


This can't work if MainViewImpl is not hosted on CEF UI thread, and this happens in demo app - it chooses multithreaded message loop on windows. So you should do it via GTK#.
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: Call on specific thread

Postby teremy » Mon Aug 29, 2016 2:37 pm

Thank you for your answer, I really appreciate that!
I guess I don't own the message loop, since I am under windows and the code says this:
Code: Select all
            if (CefRuntime.Platform == CefRuntimePlatform.Windows) Application.Run();
            else CefRuntime.RunMessageLoop();


I understand that it's therefore not possible to use PostTask, since the GTK Loop is not part of any CEF thread, but rather it's own.
Another idea of mine was to start a Thread (let's call this one main thread ) that keeps on checking if a Queue<Action> has an element and then dequeues and invokes that element.
CEF's Renderer Thread would use that Queue to add an Action to it ( enqueue ). This however does not work, the Queue has 1 element if CEF enqueues 1 Action, but the main thread still sees a Queue without an element.

Is this because chromium works not only with different threads, but it works in a different process and therefore I can't make changes to the Queue, or: I can make changes, but these changes won't affect the Queue of the main thread?
Makes sense to me, also explains why we have to use IPC in the first place.

So the thread/process that calls Application.Run(), how can I make it communicate with CEF's renderer thread? One solution would be to use IPC ( not CEF's IPC since it only allows communication with CEF threads/processes, but rather something else ) or make the GTK# loop part of a CEF loop or something like that.
teremy
Techie
 
Posts: 15
Joined: Mon Aug 22, 2016 8:51 am

Re: Call on specific thread

Postby fddima » Mon Aug 29, 2016 4:44 pm

I'm not sure that i'm understand you.

So the thread/process that calls Application.Run(), how can I make it communicate with CEF's renderer thread? One solution would be to use IPC ( not CEF's IPC since it only allows communication with CEF threads/processes, but rather something else ) or make the GTK# loop part of a CEF loop or something like that.


To post tasks into CEF threads - you can use CEF methods.
To post tasks into GTK thread - you should use GTK methods (Application class if i'm remember correctly).
So you actually don't need to have any own queue. This is enough for any kind of cross-thread communications.

As for IPC - CEF IPC is useful in most cases. You can send messages from browser to renderer process and to browser process from renderer. After what you always can route messages to correct thread if it is really needed. Of course you can establish own IPC, but CEF IPC already exists, it is know about browser and matching renderer process, so it is not a bad choice. Also i'm not sure that you really need execute most of tasks on non-main threads in browser & renderer process.

PS:
About CEF Renderer thread - it is main thread of non-browser (renderer) process. You doesn't need any foreign stuff (i mean GTK) in renderer. You can use own additional threads if you need in renderer process, but again you will use CEF methods for posting tasks into CEF threads - on different direction you always use matching impls (TPL, etc).
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: Call on specific thread

Postby teremy » Mon Aug 29, 2016 6:04 pm

Just to test some things out my goal was to use an html button to move the window.
I managed to execute a C# function when clicking on the html button. This happens in the CEF Renderer and that's why I need to tell my main process/thread to call the GTK Window's Move method, since the renderer can't make this call, otherwise the window will become white and nothing will happen.
The problem is, that the main thread/process, the one that calls Application.Run(), isn't part of any cef process/thread. That's why I can't use CEF's IPC, or at least I think so.
teremy
Techie
 
Posts: 15
Joined: Mon Aug 22, 2016 8:51 am

Re: Call on specific thread

Postby fddima » Tue Aug 30, 2016 8:05 am

1. Send message via CEF IPC to browser process.
2. Handle message, and execute action on correct thread using GTK methods.
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: Call on specific thread

Postby teremy » Tue Aug 30, 2016 6:42 pm

Ah now I understood it and it also works!
I thought PostTask could be used for IPC, but PostTask can only be used to post a task to a different thread ( but same process! ).
I use processmessage now to send a message from the renderer process to the browser process and then it works :).
Posting a task across different processes would be great though, but I guess messages work fine as well.
Thank you again very much!
teremy
Techie
 
Posts: 15
Joined: Mon Aug 22, 2016 8:51 am

Re: Call on specific thread

Postby teremy » Tue Aug 30, 2016 9:52 pm

I have another question:
Although I could get everything to work, what are the disadvantages of setting SingleProcess = true ( CefSettings )?
Sure, the performance might be a bit worse ( but not so much that it will become a problem I guess ).
It is then however much easier to hand data from renderer to the other parts of cef.
For example I want to manipulate the DOM with data I have in my browser process.
I could send this data to the renderer process, but this procedure seems very expensive/difficult, since IPC only allows me to send primitive data like int, strings etc... if I have a more complex object in my browser process, then it's a sophisticated task to send it to the renderer.
I just figured out I can also use just one single process. This way I can easily share the objects and no need to send a message to another process.
Is it ok if I do this?

I want to dynamically change the website depending on some data ( that I don't have in the rendering process, only in the browser process ). Dynamically changing the website happens in the render process, I already figured out how to do it with executing javascript or for example calling a C# function, when a button is clicked on a website.
teremy
Techie
 
Posts: 15
Joined: Mon Aug 22, 2016 8:51 am

Re: Call on specific thread

Postby fddima » Wed Aug 31, 2016 9:56 am

teremy wrote:Although I could get everything to work, what are the disadvantages of setting SingleProcess = true ( CefSettings )?

It is exists only for debugging purposes. Don't use it. By debugging purposes this better treat as it exists for debugging CEF/Chromium code, not client code. Actually it may work, but it is completely not guaranteed, it is exists cases when this mode just not work, and any errors in this mode will not be fixed, - it is not supported (in terms of bug fixing). Just forget about this mode.

teremy wrote:I want to dynamically change the website depending on some data ( that I don't have in the rendering process, only in the browser process ). Dynamically changing the website happens in the render process, I already figured out how to do it with executing javascript or for example calling a C# function, when a button is clicked on a website.

You want deliver data directly into JS, and for this purposes you don't need single process mode, and you don't need IPC (SendProcessMessage).
What really may work fine is:
a. Executing XHR requests over own schema handler (which will provide data). Better to do it, is register handler on http(s) schema on custom (virtual) domain. No actual network requests will be maden. To avoid polling - you can execute javascript which will trigger requesting data via XHR.
b. Execute javascript which holds JSON data. Works even better than (a) if you have relative small payloads.
c. Use WebSockets (doesn't like this, because application requires WebSockets server which will work over real sockets, that actually overkill).

PS: As for CefProcessMessage - inspect CefValue/CefListValue more carefully, they can hold binary data, they can be dictionaries, lists, just enough to represent almost everything reasonable.
fddima
Master
 
Posts: 788
Joined: Tue Dec 07, 2010 6:10 am

Re: Call on specific thread

Postby teremy » Fri Sep 02, 2016 10:52 pm

Thanks again for your reply, you helped me a lot!
I dont exactly know about XHR, but for me the simplest solution seems to be to use the IPC messaging between renderer and browser and use JSON. Since I can pass a string between the renderer and browser process I can easily pass any data I want ( even complex data like Lists or basically everything ) with the help of JSON.
It kinda feels like an overhead ( which it probably is ), but I guess it's fine.
teremy
Techie
 
Posts: 15
Joined: Mon Aug 22, 2016 8:51 am

Next

Return to CefGlue Forum

Who is online

Users browsing this forum: No registered users and 24 guests