The following code run in a Windows Store app blocks the UI for 30 seconds despite that fact that the loop should run in a separate thread:
int seconds(30);
// Create a thread pool
ComPtr<IThreadPoolStatics> threadPool;
HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(), &threadPool);
//
// Create an asynchronous task and start it
ComPtr<ABI::Windows::Foundation::IAsyncAction> asyncActionPtr;
hr = threadPool->RunAsync(Callback<IWorkItemHandler>( // Line 1
//
// Lambda for task. Loops doing nothing until 30 seconds have passed
[seconds](ABI::Windows::Foundation::IAsyncAction* asyncAction) -> HRESULT {
std::chrono::system_clock::time_point end(std::chrono::system_clock::now() + std::chrono::seconds(seconds)); // Line 3
while (std::chrono::system_clock::now() < end);
return S_OK; // Line 4
}).Get(), &asyncActionPtr);
if (FAILED(hr)) throw std::exception("Cannot start thread"); // Line 2
When I set breakpoints in the marked lines, I can see that Line 1 is hit before Line 2, then Line 3 and after 30 seconds Line 4. In these 30 seconds the UI is blocked and the Thread view in Visual Studio show the same thread (SHcore.dll) for all of the breakpoints.
I am using Windows 8 and Visual Studio 2012.
Can somebody explain?
Bill Messmer has given the perfect answer on MSDN. In short:
The delegate object created by Callback is not agile which means that it cannot be passed to the thread pool thread. Instead that thread receives a proxy and calls upon it are marshaled back to the delgate object in the UI thread. Bill has also given an easy fix for the problem.
Related
I am using QT 5.11.2 on both linux and windows. I am trying to optimize my UI to prevent it from freezing in large functions. I started using QThread and was able to do exactly what I want on windows. However, I tried to test the same functions on linux RHEL7 but threads never finished.
Here is what I tried:
void MainWidget::Configure_BERT_DSO(bool isOptimization, double lineRate, int Scaling)
{
QThread *bertThread = QThread::create([this, lineRate, Scaling]{ ConfigureBert(lineRate, Scaling);
QThread *dsoThread = QThread::create([this, lineRate]{ ConfigureDSO(lineRate); });
bertThread->setObjectName("My Bert Thread");
dsoThread->setObjectName("My DSO Thread");
bertThread->start();
dsoThread->start();
while(bertThread->isRunning() || dsoThread->isRunning()) // even tried isFinished()
{
qApp->processEvents();
}
bertThread->exit();
dsoThread->exit();
delete bertThread;
delete dsoThread;
}
In windows the while loop exits after a while and both threads execute correctly with no problem.
On linux, to make sure that both functions execute correctly, I added qDebug() at the start and end of each function and they are all reached at the excpected time. But the problem is that isRunning never becomes true again and the same goes for isFinished and my loop gets stuck.
Thread: QThread(0x1d368b0, name = "My Bert Thread") started.
Thread: QThread(0x1d368e0, name = "My DSO Thread") started.
Thread: QThread(0x1d368b0, name = "My Bert Thread") finished.
Thread: QThread(0x1d368e0, name = "My DSO Thread") finished.
Is it something platform dependent or is there something that I might be missing?
EDIT
I also tried to use bertThread->wait() and dsoThread->wait() to check if it exits after my functions finish but it never returns from the first one I called although both functions reach their end successfully
Your help is much appreciated
I am trying to build small application with Yew (Rustwasm) . I would like to put sleep function in Yew app.when I use use std::thread::sleep , I am getting below error
I am using sleep as below
let mut index = 0;
sleep(Duration::new(1, 0));
if col < 3 {
index = row * 4 + (col + 1);
if self.cellule[index].value == 1 {
sleep(Duration::new(1, 0));
wasm.js:314 panicked at 'can't sleep', src/libstd/sys/wasm/thread.rs:26:9
Stack:
Error
at imports.wbg.__wbg_new_59cb74e423758ede (http://127.0.0.1:8080/wasm.js:302:19)
at console_error_panic_hook::hook::hd38f373f442d725c (http://127.0.0.1:8080/wasm_bg.wasm:wasm-function[117]:0x16a3e)
at core::ops::function::Fn::call::hf1476807b3d9587d (http://127.0.0.1:8080/wasm_bg.wasm:wasm-function[429]:0x22955)
at std::panicking::rust_panic_with_hook::hb07b303a83b6d242 (http://127.0.0.1:8080/wasm_bg.wasm:wasm-function[211]:0x1ed0d)
at std::panicking::begin_panic::h97f15f2442acdda4 (http://127.0.0.1:8080/wasm_bg.wasm:wasm-function[321]:0x21ee0)
at std::sys::wasm::thread::Thread::sleep::hdd97a2b229644713 (http://127.0.0.1:8080/wasm_bg.wasm:wasm-function[406]:0x22829)
The methods like thread::sleep doesn't work, because in the JS environment you have a single thread only. If you call that sleep you will block the app completely.
If you want to use an interval you should "order" a callback. You can check the following example how to use TimeoutService or IntervalService for that: yew/examples/timer
The core idea to create a service this way:
let handle = TimeoutService::spawn(
Duration::from_secs(3),
self.link.callback(|_| Msg::Done),
);
// Keep the task or timer will be cancelled
self.timeout_job = Some(handle);
Now you can use handler of Msg::Done to react to that timer elapsed.
Threads are actually available, but it's a complex topic and you have to use Web Workers API reach them. Anyway it's useless for your case. Also there are some proposals in standards, but they aren't available in the browsers yet.
I'm working with an API that can only access its objects on the main thread, so I need to create a new thread to be used for my GUI and then swap back to the original thread for any lengthy calculations involving the API.
So far I have the following code:
[<EntryPoint; STAThread>]
let main _ =
Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] - Inital thread")
let initCtx = SynchronizationContext.Current
let uiThread = new Thread(fun () ->
let guiCtx = SynchronizationContext.Current
Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] - New UI thread")
async{
do! Async.SwitchToContext initCtx
Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] - Back to initial thread")
// Lengthy API calculation here
do! Async.SwitchToContext guiCtx
Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] - Back to UI thread")
} |> Async.RunSynchronously
)
uiThread.SetApartmentState(ApartmentState.STA)
uiThread.Start()
1
However when I run this I get the output:
[1] - Inital thread
[4] - New UI thread
[5] - Back to initial thread
[5] - Back to UI thread
So it doesn't seem to be switching contexts the way I would expect. How can I switch back to the original thread after creating a new thread this way?
I have tried calling
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher)) first to ensure that the original thread has a valid SynchronizationContext but that causes the program to exit at the Async.SwitchToContext lines without throwing any exception.
I have also tried using Async.StartImmediate instead of RunSynchronously with the same result.
If I try both of these at the same time then the program just freezes up at the Async.SwitchToContext lines instead of exiting out.
I am trying to determine if the uno-platform will work for a specific project that I want to deploy as a WebAssembly app.
I've played around with Uno and have configured the newly available threading support using:
<MonoWasmRuntimeConfiguration>threads-release</MonoWasmRuntimeConfiguration>
As I understand it, threading support is only available in Chrome and Edge at this time...but that is ok for my needs.
I've created a simple button that should spin up 10 worker threads like so:
private void Button_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10; i++)
{
var t = new Thread(() => DoWork());
t.Start();
}
}
private void DoWork()
{
for (int n = 0; n < 10000; n++)
{
Console.WriteLine($"Task {Thread.CurrentThread.ManagedThreadId} running {n}");
}
}
This code is the only thing added to the default "hello world" WASM project from the uno-platform templates.
When looking at the output, I can see that 2 threads are working as expected and interweaving results. (prior to the <MonoWasmRuntimeConfiguration>threads-release</MonoWasmRuntimeConfiguration> the output would be synchronous for a single "thread" and then synchronous for the next "thread")
Task 3 running 9987
Task 2 running 9843
Task 3 running 9988
At the completion of both threads, the follow warning is logged in the browser console.
PThread 70424616 is attempting to join to itself!
__emscripten_do_pthread_join # dotnet.js:1
_pthread_join # dotnet.js:1
mono_native_thread_join # 00806cba:0x70078
threads_native_thread_join_lock # 00806cba:0xbfd98
mono_threads_join_threads # 00806cba:0x6aefe
mono_runtime_do_background_work # 00806cba:0xdb520
mono_background_exec # 00806cba:0xf89c5
Module._mono_background_exec # dotnet.js:1
pump_message # dotnet.js:1
setTimeout (async)
_schedule_background_exec # dotnet.js:1
mono_threads_schedule_background_job # 00806cba:0x1612c
mono_threads_add_joinable_runtime_thread # 00806cba:0xd8aa4
sgen_client_thread_detach_with_lock # 00806cba:0xc67bd
thread_detach_with_lock # 00806cba:0xc0142
unregister_thread # 00806cba:0x5e469
mono_thread_info_detach # 00806cba:0xd98c6
mono_thread_info_exit # 00806cba:0x49724
start_wrapper # 00806cba:0xc1206
dynCall_ii # 00806cba:0x11d3d7
Module.dynCall_ii # dotnet.js:1
onmessage # dotnet.worker.js:1
Two questions arise which I can't find documentation about.
Why only 2 threads? (on both Chrome and Edge) Is this a browser limitation? A setting in Uno-platform?
Why do the remaining 8 threads not get started? They are essentially lost and none of the work gets performed. Is this a bug in the uno-platform? Mono? emscripten possibly?
I know threading is still experimental, but I am curious if there is a known limitation that I am hitting?
The number two may come from the default provided by emscripten, with the default number of workers provided before the main of the application. You can change the default number of threads with this:
<ItemGroup>
<WasmShellExtraEmccFlags Include="-s PTHREAD_POOL_SIZE=10"/>
</ItemGroup>
The support for threads is likely to improve a lot during the .NET 6 timeframe, so this may change signficantly.
I am developing a device driver on mac. my question is how can we make a device request asynchronous to synchronous. like i send a send encapsulated command to device and get it response using get encapsulated command after getting a notification on interrupt pipe. so how can i make my thread will wait until all above request is not completed (both send and get) . but the function from get encap is called is a virtual function and called by upper layer. so if i process a wait in that virtual function then i am not able to get response till my tread is in waiting process.
please help me to resolve this problem.
thnks in advance.
**
bool class::USBSetPacketFilter()
{
IOReturn Value
.... .................
value = send_Encasulated_command(* of structure, length);
IOLocksleepdeadline(x, y, z, w);
global variable which is updated when get_Encap is completed.
if (Value == IOSuccess &&XVZ == true)
return true;
else return false
}
**
in other function to readinterrupt pipe
pipe->Read(mMemDes,&**m_CommInfo**,NULL);
in m_CommInfo call back function we check it is a device response or not then we call get_encapsulated function to complete the request and IOLockwakeup(x,y,z) to revoke the thread
.
but when the upper layer call USBSetPacketFilter(). MY code stuck on IOLocksleepdeadline till the time out is not completed. so thread did not go to read interputpipe.