Inner task is executed in an unexpected thread - task-parallel-library

Here is some easy piece of code to show the unexpected behavior:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
_UI = TaskScheduler.FromCurrentSynchronizationContext();
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
TaskScheduler _UI;
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
{
//Expected: Worker thread
//Found: Worker thread
DoSomething();
})
.ContinueWith(t =>
{
//Expected: Main thread
//Found: Main thread
DoSomething();
Task.Factory.StartNew(() =>
{
//Expected: Worker thread
//Found: Main thread!!!
DoSomething();
});
}, _UI);
}
void DoSomething()
{
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
}
}
Why is the inner task executed in the main thread?
How can i prevent this behavior?

Unfortunately, the Current task scheduler, when you're running your continuation, becomes the SynchronizationContextTaskScheduler setup by your TaskScheduler.FromCurrentSynchronizationContext.
This is discussed in this Connect Bug - and was written this way by design in .NET 4. However, I agree that the behavior leaves a bit to be desired here.
You can work around this by grabbing a "background" scheduler in your constructor, and using it:
TaskScheduler _UI;
// Store the default scheduler up front
TaskScheduler _backgroundScheduler = TaskScheduler.Default;
public MainWindow()
{
InitializeComponent();
_UI = TaskScheduler.FromCurrentSynchronizationContext();
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
Once you have that, you can easily schedule your "background" task appropriately:
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
{
//Expected: Worker thread
//Found: Worker thread
DoSomething();
})
.ContinueWith(t =>
{
//Expected: Main thread
//Found: Main thread
DoSomething();
// Use the _backgroundScheduler here
Task.Factory.StartNew(() =>
{
DoSomething();
}, CancellationToken.None, TaskCreationOptions.None, _backgroundScheduler);
}, _UI);
}
Also, in this case, since your operation is at the end, you could just put it in its own continuation and get the behavior you want. This, however, is not a "general purpose" solution, but works in this case:
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
{
//Expected: Worker thread
//Found: Worker thread
DoSomething();
})
.ContinueWith(t =>
{
//Expected: Main thread
//Found: Main thread
DoSomething();
}, _UI)
.ContinueWith(t =>
{
//Expected: Worker thread
//Found: Is now worker thread
DoSomething();
});
}

Apart from #reed-copsey`s great answer I want to add that if you want to force your task to be executed on a threadpool thread you can also use the TaskScheduler.Default property which always refers to the ThreadPoolTaskScheduler:
return Task.Factory.StartNew(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString());
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
This way you dont have to capture the task scheduler in a variable like proposed in #reed-copsey `s answer.
More information on TaskSchedulers can be found here: TaskSchedulers on MSDN

If you want to ensure that your inner task is not run on the UI thread, simply mark it as LongRunning:
Task.Factory.StartNew(() =>
{
//Expected: Worker thread
//Found: Main thread!!!
DoSomething();
}, TaskCreationOptions.LongRunning);
That should ensure it is given its own thread instead of inlining on the current thread.

Related

Easy way to stop a task from executing after certain amount of time(Xamarin.Android)

On button click I want to open a ProgressDialog which will show until a task is being executed, but I want to be able to stop the task even if it hasn't been completed after certain amount of time. I saw a lot of solutions on internet but they are very long. I want to know if there is an easier way.
here is my On Button Click event:
private async void Btn_Click(object sender, System.EventArgs e)
{
var mDialog = new ProgressDialog(this);
mDialog.SetMessage("Loading data...");
mDialog.SetCancelable(false);
mDialog.Show();
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(5000);
Task<int> task = new Task<int>(Foo, cts.Token);
task.Start();
int integer = await task;
mDialog.Dismiss();
txtView.Text = integer.ToString();
}
And here is my method which will execute in the task:
public int Foo()
{
System.Threading.Thread.Sleep(10000);
return 100;
}
Is it possible to stop the task at the 5th second of its execution without changing a lot the code I've just pasted, for example with only passing some time or object to the task's constructor, and also without making the Foo() method async
You can try
step 1. Adding a timer
Timer _timer = new Timer {Interval = 5000};
_timer.Elapsed += OnTimeEvent;
_timer.Start();
step 2.Cancel the task on timer event
private void OnTimeEvent(object sender, ElapsedEventArgs e)
{
cts .Cancel();
}

Reactive Extensions subscribing to an observable (subject)

I'm just playing around with Reactive Extensions for the first time in a winforms application. Mind you I have been doing web development for the past 4 years, and I am very familiar with observables and observable pattern in knockout, which I am guessing is contributing to my confusion here.
Anyhow, to the question and code. I have a simple winforms experiment (see below) that I was building to illustrate my question. The subscribe below doesn't run until well after the thread in start new is finished. I can trace it the calls to OnNext, but the subscribe doesn't fire at all until sometimes 20-30 seconds later. Can somebody explain this behavior to me?
public partial class Form1 : Form
{
private Subject<int> progress;
private CancellationToken cancellationToken;
private IScheduler _scheduler;
public Form1()
{
InitializeComponent();
CancellationTokenSource source = new CancellationTokenSource();
cancellationToken = source.Token;
_scheduler = new SynchronizationContextScheduler(SynchronizationContext.Current);
}
private void Start_Click(object sender, EventArgs e)
{
progress
.ObserveOn(_scheduler)
//.Throttle(TimeSpan.FromSeconds(5))
.Subscribe(
(i) => {
progressBar1.Do<ProgressBar>(ctl =>
{
ctl.Value = i;
});
},
(ex) => { },
cancellationToken
);
Task counterTask = Task.Factory.StartNew(() =>
{
for (var i = 1; i < 101; i++)
{
Thread.Sleep(500);
progress.OnNext(i);
}
}, cancellationToken,
TaskCreationOptions.LongRunning,
TaskScheduler.FromCurrentSynchronizationContext()
);
}
private void Form1_Load(object sender, EventArgs e)
{
progress = new Subject<int>();
}
}
public static class ControlExtensions
{
public static void Do<TControl>(this TControl control, Action<TControl> action)
where TControl : Control
{
if (control.InvokeRequired)
control.Invoke(action, control);
else
action(control);
}
}
Your issue comes from the fact that your task is running on the UI thread, because you're using TaskScheduler.FromCurrentSynchronizationContext().
Hence your various Sleep calls are blocking the UI thread, freezing the UI (e.g. can't drag the window) and preventing your observable subscription to execute (because the ObserveOn, it's supposed to execute on the UI thread scheduler).
Replace TaskScheduler.FromCurrentSynchronizationContext() by TaskScheduler.Default (background TaskPool threads), and everything will work as you expected.
Note that your call to Do/Invoke is unnecessary, because you're already on the UI thread by the scheduler you've provided.

Closing stage after specific event

How do I close a stage in JavaFX 2 after some specific external event has occurred? Suppose I have a stage with a simple progress bar that is filled up by a Task (borrowed from another answer):
Task<Void> task = new Task<Void>(){
#Override
public Void call(){
for (int i = 1; i < 10; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
updateProgress(i, 10);
}
return null;
}
};
How do I close the window automatically (and open the next one) after the Task is done and the ProgressBar is filled to 100%?
Before return null; you can add
Platform.runLater(
new Runnable() {
public void run() {
stage.close();
}
}
);
or
progressBar.progressProperty().addListener(new ChangeListener<Number>(){
//add checking, that progress is >= 1.0 - epsilon
//and call stage.close();
})
The first is better. But note, that task is done on a separate thread. so you should put a request on stage.close() on JFX thread using special call.
Also, jewelsea provides links on stage closing questions in comment to the question.

callback / delegate?

i have a doubt..
i would like to create a function and it will look like this...
public class A //this is just a class file
{
function dowork()
{
//work 1
INPUT = here in this line it should call a delegate function or raise event etc...
//work 2 using INPUT
}
}
public class B
{
function myfn()
{
A objA = new A();
objA.dowork();
}
}
In the "Class A" we will raise event or so & it will display a windows form to user and then user will input some value & we need to return that value to Class A -> dowork method.... then only we should continue "work 2"
this should also support multi threading... anyone have idea how we can implement this??
thanks :)
You can use ManulResetEvent for this purpose: You run your input form and when it done that form set the event so you can catch it from A.dowork method. While the input in action you run the infinite loop, check event state and process application event to make you app responsible in this time:
public class A //this is just a class file
{
private ManualResetEvent _event;
public void dowork()
{
//work 1
_event = new ManualResetEvent(false);
//INPUT = here in this ...
Worker worker = new Worker();
worker.DoInput(_event);
while(true)
{
if(_event.WaitOne())
break;
Application.DoEvents();
}
//work 2 using INPUT
}
}
class Worker
{
private ManualResetEvent _event;
public void DoInput(ManualResetEvent #event)
{
_event = #event;
// Show input form here.
// When it done, you call: _event.Set();
}
}
Also, I suggest you (if you can) use Async library (it is available as a standalone setup). There you can implement it in much more straightforward way:
public class A //this is just a class file
{
public async void dowork()
{
//work 1
//INPUT = here in this ...
Worker worker = new Worker();
wait worker.DoInput();
//work 2 using INPUT
}
}
class Worker
{
public async void DoInput()
{
InputForm form = new InputForm();
wait form.ShowInput();
}
}
public class B
{
async void myfn()
{
A objA = new A();
wait objA.dowork();
}
}
As you see you just wait while other piece of code get executed without any UI locking and events.
I can provide deeper explanation of how async/wait works here if you need.

Real time java - async event handler fails to fire

The following code is adapted from an example in Real-Time Java Platform Programming by Peter C. Dibble:
import javax.realtime.*;
public class OSTimer {
static volatile boolean cont = true;
public static void main(String[] args) {
AsyncEventHandler handler = new AsyncEventHandler(){
public void handleAsyncEvent() {
System.out.println("Stopping...");
cont = false;
}
}
};
OneShotTimer timer = new OneShotTimer(new RelativeTime(3000, 0), handler);
timer.start();
while(cont){
System.out.println("Running");
if (timer.isRunning()) System.out.println("Timer is running");
try {
Thread.sleep(1000);
} catch(Exception e) { }
}
System.exit(0);
}
The the program is supposed to run for 3 seconds and then exit. However, the output shows that while the timer did indeed stop after 3 seconds, the program continues as usual, i.e. output is:
Running
Timer is running
Running
Timer is running
Running
Timer is running
Running
Running
Running......
Clearly the handler did not fire, and I've no idea why. Another example program involving a periodic timer triggering the handler does work as expected. The program structure is almost the same as the one here.
A few things to try:
Call fire() explicitly on the timer instance to see if you can force things
Try creating your handler by passing in the logic as a Runnable object to the handler. The API is a little unclear on this, but this is how I have specified handlers in the past.
Example:
AsyncEventHandler handler = new AsyncEventHandler(new Runnable() {
public void run() {
System.out.println("Stopping...");
cont = false;
}
});

Resources