Does threading in c# carry to other methods? - c#

Issue
I am streaming my camera out and want it to run on a separate thread as my UI is freezing. If I start a Thread on the first method call, does the methods inside that method go into the new thread or the old thread?
This is my setup at the moment.
Code
When the user clicks 'Start Stream':
Thread thread = new Thread(new ThreadStart(StartNewStream));
thread.Name = "streammm";
thread.Start();
This calls 'StartNewStream' method which calls other methods:
cam.OnSampleAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushVideo(e.Sample);
};
win.OnSamplesAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushAudio(e.Samples);
};
Do the methods PushVideo and PushAudio get called in the UI thread or the newly created thread?
If I go into the PushVideo method and put the code:
Thread TR = Thread.CurrentThread;
string _name = TR.name;
The name is now null?
Anyone help on what I am doing wrong?

Whichever thread invokes the OnSampleAvailable event or delegate will also execute its handlers. It does not matter which thread assigns the handlers.
You must understand what your code actually does:
cam.OnSampleAvailable += (s, e) =>
{
lock (BusyLock)
rtspRecord.PushVideo(e.Sample);
};
This does not call anything at first. It only assigns an anonymous method (s, e) => { ... } as a handler to the event cam.OnSampleAvailable.
The handler is not called here. The assignment completes and as the end of your StartNewStream method is reached, your new thread ends. Then, much later, there may be samples available on your cam. Whichever thread is responsible (we do not know) will invoke the cam.OnSampleAvailable event, and the handler (the anonymous method (s, e) => { ... } you assigned earlier) will be executed by that unknown thread.

It depends on the implementation of cam and win. Likey either those two events are running on their own thread pool thread or they may run on the UI thread if they are written in a way that knows how to capture the OperationContext

Related

Scope of variable in different thread at runtime

Consider the below code:
public void MyMethod()
{
bool flag=true;
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (x, y) =>
{
//time consuming task
if (flag)
{
//do something
}
};
worker.RunWorkerCompleted += (x, y) =>
{
if (flag)
{
//do something
}
};
worker.RunWorkerAsync();
}
Perhaps a stupid question, but as I can understand, after runworkerasync call, the dowork event is raised which runs its method on a different thread. Is checking the value of the local variable flag safe inside the dowork eventhandler since I feel the code exits MyMethod after calling worker.RunWorkerAsync?
There's no problem with flag here because of a concept called Closures. However, especially with threads this can be dangerous (use your favourite search engine).
Depending on your definition of 'safe', it is possible to check the local variable flag within DoWork as it remains in scope for that method. Having said that it may not necessarily be thread safe.

Why does the BackgroundWorker not call the RunWorkerCompleted on the right thread in this unit test?

The whole point of the backgroundWorker is to update the UI after a time-consuming task. The component works as advertised in my WPF app.
However in my test, the callback is not invoked on the calling thread.
[Test]
public void TestCallbackIsInvokedOnClientThread()
{
var clientId = Thread.CurrentThread.ManagedThreadId;
int callbackThreadId = -1;
var manualEvent = new ManualResetEventSlim(false);
var someUIControl = new TextBox();
var bw = new BackgroundWorker();
bw.DoWork += (s,e) => e.Result = 5 ; // worker thread
bw.RunWorkerCompleted += (s, e) =>
{
try
{
callbackThreadId = Thread.CurrentThread.ManagedThreadId;
//someUIControl.Text = callbackThreadId.ToString();
manualEvent.Set();
}
catch (System.Exception ex)
{
Console.Out.WriteLine(ex.ToString());
}
};
bw.RunWorkerAsync();
if (!manualEvent.Wait(5000))
Assert.Fail("no callback");
Assert.AreEqual(clientId, callbackThreadId);
}
Result Message: Assert.AreEqual failed. Expected:<15>. Actual:<10>. callback not invoked on client Thread
What am I missing ?
In the Unit Test I see behavior like
------ Run test started ------
MainThread Id =21
Worker Thread Id =9
Callback Thread Id =9
In the Wpf App, this would be
MainThread Id =1
Worker Thread Id =14
Callback Thread Id =1
Update:
With Justin's answer, made the following changes and now the test passes
Before creating the BackgroundWorker
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(control.Dispatcher));
Instead of using a event for signalling between the threads, simulate a message pump
.
for (int i = 0; i < 3; i++)
{
control.Dispatcher.Invoke(DispatcherPriority.Background,
new Action(delegate { }));
Thread.Sleep(50);
}
The behavior is different dues to the different contexts that you are running under.
When you call bw.RunWorkerAsync(), the SynchronizationContext is captured. This is used to dispatch out the RunWorkerCompleted call.
Under WPF it will use DispatcherSynchronizationContext which will marshall the completed call back to the UI thread. Under the test, this marshalling is unnecessary so it remains on the background worker thread.
I belive that the calling thread must support messagepumping (mean, being STA apartment and having an associated Dispatcher) so the background worker can post the callback. If it does not, the background worker has no option but execute the callback in its own thread. If you want to test it, see this link.
I ran into a problem in my code where the user closing a window caused a save, that in turn used a BackgroundWorker to update the home window and it did not run the RunWorkerCompleted because the thread that started the BackgroundWorker had terminated when the window closed.
I had to change the closing window's save run in the home window's context so that after the BackgroundWorker completed, it had a thread to return to.
In my case I am using Windows Forms and controls don't have a Dispatcher property (see the answer in no definition for dispatcher).
Gishu's solution works as well if we use Dispatcher.CurrentDispatcher instead of the one in the control.
On test initialisation:
// I am using a field Dispatcher _dispatcher
_dispatcher = Dispatcher.CurrentDispatcher;
And then when waiting for the background task to be completed:
_dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
Thread.Sleep(50);

Attempted to read or write protected memory. This is often an indication that other memory is corrupt

I really do not understand how is this error happening at this code. Please check the code yourself
void dispatcherTimer_Tick(object sender, EventArgs e)
{
string srUrl = lstLocalIndex[irLocalIndex] + lstMainIndex[irMainIndex].Replace("0;","");
Task.Factory.StartNew(() =>
{
startNewWindow(srUrl);
});
}
void startNewWindow(string srUrl)
{
NewWindowThread<TitleWindow, string>(c => new TitleWindow(c), srUrl);
}
Now this code is where the error happening. I will also attach screenshot
private void NewWindowThread<T, P>(Func<P, T> constructor, P param) where T : Window
{
Thread thread = new Thread(() =>
{
T w = constructor(param);
w.Show();
w.Closed += (sender, e) => w.Dispatcher.InvokeShutdown();
try
{
System.Windows.Threading.Dispatcher.Run();
}
catch
{
}
});
thread.SetApartmentState(ApartmentState.STA);
try
{
thread.Start();
}
catch
{
}
}
This error causes whole software throw error and stop working even though i am calling them in new thread :(
This line throwing error System.Windows.Threading.Dispatcher.Run();
Please check also screenshot
C# 4.0 WPF
I have been battling this issue with a customer and here is what I found.
We are working on a WPF application that does a lot of threading and background worker processing. This exception suddenly started cropping up and I started doing some digging. I finally found the culprit after about an hour of investigating:
var worker = new BackgroundWorker();
worker.DoWork += (o, ea) => Dispatcher.BeginInvoke(new Action(() =>
{
//do some heavy processing here, plus UI work, then call another method.
//inside that other method, I found this:
var thread = new Thread(() =>
{
//do some heavy processing.
}) { IsBackground = true };
thread.Start();
}));
What appears to have been happening is that the background worker is finishing its work and returning from its execution. However, the thread that is created inside that background worker isn't done processing and returns only to find that the thread it was created on has already gone out of scope, thus resulting in the AccessViolationException.
In order to debug this, I would suggest paying close attention to where the exception happens and closely examining your call stack, which may or may not have been destroyed or lost depending upon whether or not you are inside a thread when the exception gets thrown.
You are using a lambda as a thread function. This lambda is called on a new thread. At the
moment the thread is actually created, it will look for the argument you supply, which is a local variable srUrl, but by the time this happens your function (dispatcherTimer_Tick) has already exited, so srUrl will be in a part of the stack that is no longer properly defined (hence the access violation). The easy fix is to define a variable in the class and stuff the srLoc there quickly. A more proper solution is to actually pass the srLoc as argument:
() =>
{
startNewWindow(srUrl);
}
becomes
(Action<string>){x => {startNewWindow(x);},
new object[] {srUrl}
Now the function reference and a proper copy of the string are saved for the function call, and it doesn't matter that the original srUrl is out of scope by the time the thread kicks in. I'm not sure whether the task factory allows the argument array to be passed. dispatchers normally have an overload for this, so maybe you want to let your window take care of this.
Now you actually do this a few times, so you may need to wrap the arguments each time they are passed.
I had similar problem some time ago.
The error occurs because your window goes out of scope and Garbage Collector destroys it.
Using ShowDialog() should solve the issue. Note that doing this won't block other threads because the window will be modal in the calling thread only.
private void NewWindowThread<T, P>(Func<P, T> constructor, P param) where T : Window
{
Thread thread = new Thread(() =>
{
System.Windows.Threading.Dispatcher.Run();
T w = constructor(param);
w.ShowDialog();
w.Dispatcher.InvokeShutdown();
});
thread.SetApartmentState(ApartmentState.STA);
try
{
thread.Start();
}
catch
{
// log&handle exceptions
}
}

Theads to keep alive a process but useless otherwise

Hello guys I have a question regardless a old code a client needed a update.
This code add a thread.sleep(500) to keep the service alive, is reading from a com port some calls, and sending a alarm to other pcs now this time when I was sending some information to the machine in question this error pops out
Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) {
Thread.Sleep(500);
string data = port.ReadExisting();
//try
//{
if (textBox1.TextLength == 30000)
{
textBox1.Text = "";
}
//}
//catch (Exception) {}
this.BeginInvoke(new setTextDeleg(si_DataRecived), new object[]{
data});
}
This is the function that writes on the com machine, does making a exception to eat the error is ok, or is there another better way to handle it?
PD: Sorry for my bad english, this is on C# 2008 vs
You should modify GUI components like textboxes and labels only from the thread that created them which is the main thread. You may take a look at BackgroundWorker which simplifies this task in WinForms application. And here's another useful article illustrating the usage of the InvokeRequired property and the Invoke method.
It's not a good idea to simply swallow this exception. The exception is occurring because you are not allowed to modify UI components from any thread other than the UI thread (the thread that created them). Instead, check out this MSDN article on how to pass information between worker threads (your thread that sleeps) and UI threads to update the text box in the correct manner.
The problem is because Windows Forms Controls are not thread-safe, and it would seem that the control is not being invoked properly for a thread-safe call. You can use the BackgroundWorker class or you can invoke it yourself. Here is a small code example.
// Delegate used by our worker thread to invoke our control
private delegate void ProgressDelegate(int value);
// Callback method used for our delegate
private void ProgressCallback(int value) {
progressBar1.Value = value;
}
protected override void OnShown(EventArgs e) {
Thread thread = new Thread(new ThreadStart(MyThreadWorker));
thread.IsBackground = true;
thread.Start();
}
// Thread method
private void MyThreadWorker() {
// Setup the delegate
ProgressDelegate mydelegate = new ProgressDelegate(ProgressCallback);
// Do some work
int pos = 0;
do {
pos++;
// Make a thread-safe call to our control and invoke our callback on the original thread
// Original thread: The thread the form and control were created on
progressBar1.Invoke(mydelegate, pos);
} while (pos < 100);
}
I'm guessing what some of your other code looks like, but you could probably move this
if (textBox1.TextLength == 30000)
{
textBox1.Text = "";
}
to the si_DataRecived method, so that it gets executed as part of the BeginInvoke call, the target of which will execute on the main (UI) thread.

C# threading issue

To play a bit with threading, delegates and backgroundworkers, I'm putting together a few small applications, I'm having a bit of trouble with one of them.
I've a Windows form, with a textbox, a button and a richttext.
When I press the button, the text in the textbox is used as a paramter to instantiate a class, like this:
public partial class Form1 : Form
{
private BackgroundWorker backgroundWorker;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(worker_DoWork);
backgroundWorker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
new Thread((ThreadStart)delegate()
{
this.BeginInvoke((ThreadStart)delegate()
{
foreach (string line in textBox1.Lines)
{
Dig digger = new Dig(line, textBox1.Text);
digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker);
string response = digger.GetAllInfo();
richTextBox1.AppendText(response);
Application.DoEvents();
}
});
}).Start();
}
void OnUpdateTicker(string msg)
{
new Thread((ThreadStart)delegate()
{
this.BeginInvoke((ThreadStart)delegate()
{
label4.Text = msg;
Application.DoEvents();
});
}).Start();
}
}
When debugging I run into a 'textBox1.Lines' threw an exception of type 'Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException'
Any tips on how to solve this problem?
First, there is no need to create new threads inside DoWork; the whole idea with the BackgroundWorker is that DoWork is executed on a separate thread. Second, since DoWork is executed on a separate thread and UI controls can be modified only on the UI thread, you need to invoke those updates correctly. So, a rewritten version of worker_DoWork could look like this:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (string line in textBox1.Lines)
{
Dig digger = new Dig(line, textBox1.Text);
digger.DomainChecked += new Dig.DomainCheckedHandler(OnUpdateTicker);
string response = digger.GetAllInfo();
richTextBox1.Invoke((Action) delegate { richTextBox1.AppendText(response); });
}
}
Note how the code does not explicitly spawn any new threads, and also how the AppendText method call is done through a Control.Invoke call, forcing it to execute on the UI thread.
The main reason is that the textbox is not owned by the background thread.
Your UI thread owns all the UI objects, and you're spinning up a background thread when a button is pressed. That background thread should not have access to any UI objects.
If you want the value of the textbox to be used, you'll need to pass it to your background thread another way.
Have a look here for an explanation (and solution).
You can only update controls on the main thread from the main thread itself, unless you explicitly tell your program that it's ok to do, by using the .Invoke method of the control.
From: http://www.albahari.com/threading/part3.aspx
Control.Invoke
In a multi-threaded Windows Forms application, it's illegal to call a method or property on a control from any thread other than the one that created it. All cross-thread calls must be explicitly marshalled to the thread that created the control (usually the main thread), using the Control.Invoke or Control.BeginInvoke method. One cannot rely on automatic marshalling because it takes place too late – only when execution gets well into unmanaged code, by which time plenty of internal .NET code may already have run on the "wrong" thread – code which is not thread-safe.

Categories

Resources