Why is the callback not reached straight away? - c#

Please see the code below:
public partial class Form1 : Form
{
SynchronizationContext sc;
public Form1()
{
InitializeComponent();
sc = SynchronizationContext.Current;
var _threadStart = new ThreadStart(LongProcess);
var _thread = new Thread(_threadStart);
_thread.Start();
//simulate a time consuming operation.
for (long l=0; l<100000000000000; l++)
{
}
}
private void callback()
{
Console.WriteLine("Reached callback method");
}
private void LongProcess()
{
sc.Post(
(o) => callback(), null);
}
}
The callback function is only reached after the Form1 constructor has finished. Is it possibe for the callback to be reached whilst the constructor is still running?

Nope, you've queued it back to the same thread (via sc.Post) and it cannot run until that thread gets a chance to pump messages.
You've moved one time-consuming operation to a background thread, why not do the same for the second one?

Related

ManualResetEvent strange behaviour

Before asking, I'll first show some code...
public partial class Player : UserControl
{
ManualResetEvent _pauseEvent;
ManualResetEvent _stopEvent;
Thread t;
public Player()
{
InitializeComponent();
this.Disposed += (s, a) =>
{
Quit();
};
_pauseEvent = new ManualResetEvent(true);
_stopEvent = new ManualResetEvent(false);
// Creates the thread...
t = new Thread(StartText);
t.IsBackground = false;
// Starts with thread paused...
StopPlaying();
// Let's go!
t.Start();
}
public void StopPlaying()
{
Console.WriteLine("Ordered to stop");
_pauseEvent.Reset();
}
private void ResumePlaying()
{
Console.WriteLine("Ordered to resume");
_pauseEvent.Set();
}
public void Quit()
{
_pauseEvent.Set();
_stopEvent.Set();
}
public void SetText(string text, bool loop)
{
StopPlaying();
// Here we supose the thread would be stopped!!!! But it's not!!!
// But when I call StopPlaying() from a button on the form that
// contains this usercontrol, everything works as expected
...... Do some processing here .....
ResumePlaying();
}
private void StartText()
{
while (true)
{
_pauseEvent.WaitOne(Timeout.Infinite);
if (_stopEvent.WaitOne(0))
break;
do // While LOOP
{
... Do some process here .....
// Verifies if stop requested
if (!_pauseEvent.WaitOne(0))
{
Console.WriteLine("STOP REQUESTED");
break;
}
}
} while (LOOP);
}
}
}
My problem is:
When I call StopPlaying() from a button of the form that contains this UserControl, the test made inside the thread detects correctly, but when I call StopPlaying from the SetText() method it doesn't work, as if the event is not resetted.
By the way, the method SetText() is called by another button of the same form.
It looks like you have a race condition in your StartText() method. You have StartText running on a separate thread and SetText() is called from the main UI thread, so what's probably happening is that SetText() is resetting and then setting _pauseEvent before control is passed back to the other thread. So as far as StartText is concerned the reset never happens.

Thread updating GUI freezes in random moments

I have form with button and text box. Button is starting thread which is updating value of text box.
public Form1()
{
InitializeComponent();
myDelegate = new UpdateUi(updateUi);
}
private void button1_Click(object sender, EventArgs e)
{
myThread = new Thread(new ThreadStart(ThreadFunction));
myThread.Start();
}
private void ThreadFunction()
{
MyThreadClass myThreadClassObject = new MyThreadClass(this);
myThreadClassObject.Run();
}
private void updateUi(int i)
{
textBox1.Text = i.ToString();
Thread.Sleep(1000);
}
public Thread myThread;
public delegate void UpdateUi(int i);
public UpdateUi myDelegate;
and ThreadClass:
public class MyThreadClass
{
Form1 myFormControl1;
public MyThreadClass(Form1 myForm)
{
myFormControl1 = myForm;
}
public void Run()
{
// Execute the specified delegate on the thread that owns
// 'myFormControl1' control's underlying window handle.
for(int i=0;i<100;i++)
{
if(myFormControl1.InvokeRequired)
{
myFormControl1.Invoke(myFormControl1.myDelegate,i);
}
}
}
}
As You can see there is nothing special in my code but sometimes the code freeze.
eg it goes 1->2->3->freeze->16->17 and so on.
I took code from HERE with little modifications
The issue is you are delaying the UI thread not the the process itself so what happens is you issue all the update commands but since it all runs on the same thread it gets clogged because the Thread.Sleep stops the UI thread so it runs a bunch of textBox1.Text = i.ToString(); then it stops for all the time of all the Thread.Sleep(1000); probably the number of 1->2->3... you see is equal to the number of cores in your machine.
When you stop the run method what happens is you issue one update command that runs immediately and wait for one second until you issue the next command witch I think its what you are trying to accomplish.

Communication between threads via delegates?

I am looking for a solution for interthread communication.
Thread A is the main thread of a windows app. I starts a Thread B that is working independant of thread a, they do not share code. But thread A has to get some feedback about status of thread b. I try to solve this with a delegate.
I am very sorry, I forgot to add that I have to work on .net 3.5, c#, WEC7
It is important that the code
public void OnMyEvent(string foo)
{
MessageBox.Show(foo);
}
is executed in context of thread a, how can I achieve this
public partial class Form1 : Form
{
//...
public void StartThread(Object obj)
{
new ClassForSecondThread(obj as Parameters);
}
private void button1_Click(object sender, EventArgs e)
{
//ParameterizedThreadStart threadstart = new ParameterizedThreadStart(startThread);
ParameterizedThreadStart threadstart = new ParameterizedThreadStart(StartThread);
Thread thread = new Thread(threadstart);
Parameters parameters = new Parameters(){MyEventHandler = OnMyEvent};
thread.Start(parameters);
}
public void OnMyEvent(string foo)
{
MessageBox.Show(foo);
}
}
//This code is executed in Thread B
public class ClassForSecondThread
{
public ClassForSecondThread(Parameters parameters)
{
if (parameters == null)
return;
MyEventhandler += parameters.MyEventHandler;
DoWork();
}
private void DoWork()
{
//DoSomething
if (MyEventhandler != null)
MyEventhandler.DynamicInvoke("Hello World");// I think this should be executed async, in Thread A
Thread.Sleep(10000);
if (MyEventhandler != null)
MyEventhandler.DynamicInvoke("Hello World again"); // I think this should be executed async, in Thread A
}
public event MyEventHandler MyEventhandler;
}
public class Parameters
{
public MyEventHandler MyEventHandler;
}
public delegate void MyEventHandler(string foo);
As you want to call the MessageBox on the main UI thread, you can achieve what you want using Control.Invoke.
Invoke((MethodInvoker)(() => MessageBox.Show(foo)));
The Invoke method can be called directly on the Form and you won't be in the context of Thread B within the delegate - the code will run on the same thread as the Form.
EDIT:
OP question: if I understood Control.Invoke correctly, it always acts in the context of a control?
Although the Invoke method uses a Control (in this case the form) to get a handle to the UI thread it is running on, the code within the delegate is not specific to the UI. If you want to add more statements and expand it to include more stuff, just do this:
string t = "hello"; //declared in the form
//Thread B context - Invoke called
Invoke((MethodInvoker)(() =>
{
//Back to the UI thread of the Form here == thread A
MessageBox.Show(foo);
t = "dd";
}));
Also, if you are updating things in a multi threaded environment where the data is accessible to more than one thread, then you will need to investigate sychronization - applying locks to data etc.
For what it is worth you can simplify your code considerably by using the new async and await keywords in C# 5.0.
public class Form1 : Form
{
private async void button1_Click(object sender, EventArgs args)
{
OnMyEvent("Hello World");
await Task.Run(
() =>
{
// This stuff runs on a worker thread.
Thread.Sleep(10000);
});
OnMyEvent("Hello World again");
}
private void OnMyEvent(string foo)
{
Message.Show(foo);
}
}
In the code above OnMyEvent is executed on the UI thread in both cases. The first call be executed before the task starts and the second call will be executed after the task completes.

Console application doesn't obey Thread.Join

I'm having trouble understanding why my console app doesn't wait until the thread it spawns fully terminates. I think this is related to the fact that the thread in question also spawns its own child threads and/or the inclusion of System.Timer
The basic program flow is as follows. Main creates a new thread against the Simulator.Start method, and then joins until that thread terminates. Simulator.Start creates a new Timer (to constrain how long it should execute) and then creates/runs a bunch of child threads. When the Elapsed event is raised by the Timer, this signals that the Simulator should terminate all of its child threads and generate a report. The problem is that the console app exits as soon as all child threads terminate and the code to generate a report never gets executed (See Simulator.Stop method below).
Hopefully some pseudo code will help:
public class Program
{
private static Simulator _simulator;
private static void Main(string[] args)
{
var options = new SimulationOptions();
//check for valid options
if (!Parser.Default.ParseArguments(args, options)) return;
_simulator = new Simulator(options);
var thread = new Thread(_simulator.Start) {IsBackground = false};
thread.Start();
thread.Join();
}
}
public class Simulator
{
private readonly SimulationOptions _options;
private readonly List<Thread> _threads = new List<Thread>();
private readonly List<Worker> _workers = new List<Worker>();
private static Timer _timer;
public Simulator(SimulationOptions options)
{
_options = options;
StartTimer(_options.LengthOfTest);
}
private void StartTimer(int lengthOfTest)
{
_timer = new Timer {Interval = lengthOfTest*1000};
_timer.Elapsed += Timer_Elapsed;
_timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
_timer.Stop();
Stop();
}
public void Stop()
{
// Request that the worker thread stop itself:
foreach (Worker worker in _workers)
{
worker.RequestStop();
}
GenerateReport(); //<-- this code never gets executed
}
private XDocument GenerateReport()
{
//build an awesome report
}
public void Start()
{
_threads.Clear();
_workers.Clear();
for (int i = 0; i < _options.NumberOfClients; i++)
{
_workers.Add(new Worker());
_threads.Add(new Thread(_workers.Last().PumpMessages));
_threads.Last().Start();
}
}
}
public class Worker
{
private bool _shouldStop = false;
public void PumpMessages()
{
while (!_shouldStop)
{
//does cool stuff until told to stop
}
}
public void RequestStop()
{
_shouldStop = true;
}
}
Nothing in your start method keeps the thread alive. When the following method finishes, so does the thread. You then call Thread.Join and that is the end of that.
public void Start()
{
_threads.Clear();
_workers.Clear();
for (int i = 0; i < _options.NumberOfClients; i++)
{
_workers.Add(new Worker());
_threads.Add(new Thread(_workers.Last().PumpMessages));
_threads.Last().Start();
}
}
If you intend on waiting for this work to complete, consider waiting on a ManualResetEvent for each worker thread that you are using.
http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx
http://msdn.microsoft.com/en-us/library/system.threading.waithandle.waitall.aspx
Your method should look something like the following.
public void Start()
{
_threads.Clear();
_workers.Clear();
var evts = new List<ManualResetEvent>()
for (int i = 0; i < _options.NumberOfClients; i++)
{
ManualResetEvent evt = new ManualResetEvent(false);
evts.Add(evt);
_workers.Add(new Worker(evt));
_threads.Add(new Thread(_workers.Last().PumpMessages));
_threads.Last().Start();
}
WaitHandle.WaitAll(evts.ToArray());
}
public class Worker
{
private bool _shouldStop = false;
private readonly ManualResetEvent #event;
public Worker(ManualResetEvent #event)
{
this.#event = #event;
}
public void PumpMessages()
{
while (!_shouldStop)
{
//does cool stuff until told to stop
}
#event.Set();
}
public void RequestStop()
{
_shouldStop = true;
}
}
Join method waits only for thread instance you joined, so Simulator.Start just creates some threads and it terminates, as the result Join returns and your main thread terminates. But still your App is alive(reason some other Foreground threads are still running).
generate a report never gets executed? Why?
Process will terminate when all Foreground Threads terminates. so as soon as your child threads return from PumpMessages method when you call RequestStop in a loop, all of your foreground threads terminates
public void Stop()
{
// Request that the worker thread stop itself:
foreach (Worker worker in _workers)
{
worker.RequestStop();
}
<--here all foreground threads are ready to terminate
GenerateReport(); //<-- this code never gets executed
}
It was little misleading that I stated that all foreground threads die after the loop. To make it clear let's say that we have given instruction for the worker threads to stop working, so all threads may or may not die before executing GenerateReport method. yes there is a Race If worker threads wins the race then we lose it, and viceversa. sometimes your GenerateReport may execute without any problem.
How to fix it? We just wait for all our worker threads to terminate. that's it.
public void Start()
{
_threads.Clear();
_workers.Clear();
for (int i = 0; i < _options.NumberOfClients; i++)
{
_workers.Add(new Worker());
_threads.Add(new Thread(_workers.Last().PumpMessages));
_threads.Last().Start();
}
foreach (var t in _threads)
t.Join();
}

How to stop a service when a thread is doing work (without using Thread.Abort)

I have a service running some different tasks in a loop until the service is stopped.
However one of these tasks i calling a web service and this call can take several minutes to complete. I want to be able to stop the service instantly, 'cancelling' the web service call without calling Thread.Abort because that causes some strange behavior even if the only thing the thread is doing is calling this web service method.
How can i cancel or break from a synchronous method call (if it's even possible)?
Or should I try a different approach?
I have tried to use the AutoResetEvent and then calling Thread.Abort which is working fine in the below code sample, but when implementing this solution in the actual service I get some unexpected behavior probably because of what's going on in the external libraries I'm using.
AutoResetEvent and Thread.Abort:
class Program
{
static void Main(string[] args)
{
MainProgram p = new MainProgram();
p.Start();
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Q)
p.Stop();
}
}
class MainProgram
{
private Thread workerThread;
private Thread webServiceCallerThread;
private volatile bool doWork;
public void Start()
{
workerThread = new Thread(() => DoWork());
doWork = true;
workerThread.Start();
}
public void Stop()
{
doWork = false;
webServiceCallerThread.Abort();
}
private void DoWork()
{
try
{
while (doWork)
{
AutoResetEvent are = new AutoResetEvent(false);
WebServiceCaller caller = new WebServiceCaller(are);
webServiceCallerThread = new Thread(() => caller.TimeConsumingMethod());
webServiceCallerThread.Start();
// Wait for the WebServiceCaller.TimeConsumingMethod to finish
WaitHandle.WaitAll(new[] { are });
// If doWork has been signalled to stop
if (!doWork)
break;
// All good - continue
Console.WriteLine(caller.Result);
}
}
catch (Exception e)
{
Console.Write(e);
}
}
}
class WebServiceCaller
{
private AutoResetEvent ev;
private int result;
public int Result
{
get { return result; }
}
public WebServiceCaller(AutoResetEvent ev)
{
this.ev = ev;
}
public void TimeConsumingMethod()
{
try
{
// Simulates a method running for 1 minute
Thread.Sleep(60000);
result = 1;
ev.Set();
}
catch (ThreadAbortException e)
{
ev.Set();
result = -1;
Console.WriteLine(e);
}
}
}
Can someone suggest a solution to this issue?
Try this
public void Start()
{
workerThread = new Thread(() => DoWork());
doWork = true;
workerThread.IsBackground = true;
workerThread.Start();
}
A thread is either a background thread or a foreground thread.
Background threads are identical to foreground threads, except that
background threads do not prevent a process from terminating. Once all
foreground threads belonging to a process have terminated, the common
language runtime ends the process. Any remaining background threads
are stopped and do not complete.
For more details see http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx
The solution is really this simple: Don't make calls that block for several minutes unless you want to block for several minutes. If there is no way to do a particular thing without blocking, potentially for several minutes, complain loudly to whoever wrote the code that imposes that painful requirement (or fix it yourself, if possible).
Once you've made the call, it's too late. You're committed. If the function you are calling doesn't provide a safe way to abort it, then there's no safe way.
As all you want to do is make one an asynchonrous web service call at a time and on each response make another call you can dispense with the worker thread and simply make an aynchronous call, register a callback and make another async call from the callback:
class Program
{
private static WebServiceCaller.TCMDelegate _wscDelegate;
private static readonly WebServiceCaller _wsCaller = new WebServiceCaller();
static void Main(string[] args)
{
_wscDelegate = _wsCaller.TimeConsumingMethod;
MakeWSCallAsync();
Console.WriteLine("Enter Q to quit");
while (Console.ReadLine().ToUpper().Trim()!="Q"){}
}
public static void MakeWSCallAsync()
{
_wscDelegate.BeginInvoke(OnWSCallComplete, null);
}
public static void OnWSCallComplete(IAsyncResult ar)
{
Console.WriteLine("Result {0}", _wscDelegate.EndInvoke(ar));
MakeWSCallAsync();
}
}
class WebServiceCaller
{
public delegate int TCMDelegate();
public int TimeConsumingMethod()
{
try
{
// Simulates a method running for 1 minute
Thread.Sleep(1000);
return 1;
}
catch (ThreadAbortException e)
{
return -1;
}
}
}
No blocking (well, the console thread is blocking on ReadLine()) and no windows kernal mode sync objects (AutoResetEvent) which are expensive.

Categories