This question already has answers here:
How do I update the GUI from another thread?
(47 answers)
Closed 9 years ago.
Short Version :
I need to pass complex data back and forth between threads, 1 thread being a WinForm, the other thread calling an online translator service and changing all the data the Winform uses.
Long Version :
Passing large amounts of data to an online translator service was freezing up my front end for minutes at a time, so I'm trying to move that logic into a thread. The Winform makes extensive use of the data that the online service needs to process and return with new info attached.
I was using this code to kick off the thread :
threadWork tw = new threadWork(); //obj to hold data for thread
tw.settings = frmMain.projectSettings;
tw.CompletedEvent += tw_CompletedEvent; // callback event, returns data
ThreadPool.QueueUserWorkItem(doWork,tw); // kick off thread
receiving callback code :
void tw_CompletedEvent(projectFormat settings)
{
frmMain.projectSettings = settings;
NotifyLoadTransationKeys(frmMain.projectSettings.translationKeys,frmMain.projectSettings.translatedLanguages);
}
which basically created this error :
Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on. [on frmMain]
so I found this suggesting an alternative use of [STAThread] [sta = single thread apartment] inside Program.cs (default c# winform entry point)
using System.Threading;
Thread t = new Thread(new ThreadStart(StartNewStaThread));
// Make sure to set the apartment state BEFORE starting the thread.
t.ApartmentState = ApartmentState.STA;
t.Start();
private void StartNewStaThread() {
Application.Run(new Form1());
}
Everything in my C# app starts in 'Program.cs' so I tried the above suggestion like so :
static class Program
{
public static translationUtil TranslationUtil; //location of time intensive webservice
public static projectFormat projectSettings; //data that needs sharing
static void Main() // prog entry point
{
ProgramCode pc = new ProgramCode();
pc.Main();
}
}
class ProgramCode
{
public void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Thread t = new Thread(new ThreadStart(StartNewStaThread));
t.ApartmentState = ApartmentState.STA;
t.Start();
}
private void StartNewStaThread()
{
Application.Run(new Main());
}
}
in the code above I've tried to move the shared resources to 'Program.cs' and then created a new class and thread to hold my winform,but this still gives me cross threading issues (same error as before)! Has anybody got an suggestions as to how to use threads and share data successfully in my situation?
Update : #HenkHolterman answered my question best thus far, but I've come across this code many times after researching the answer he has given me (using "invoke")
if (control.InvokeRequired) {
control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text}); // invoking itself
} else {
control.Text=text; // the "functional part", executing only on the main thread
}
Follow on question... the 'if' statement above appears to just set the text without invoke (on one of the branches of the 'if', should I follow this pattern as well, what is it for?
Your basic solution:
void tw_CompletedEvent(projectFormat settings)
{
frmMain.projectSettings = settings;
frmMain.Invoke( () =>
NotifyLoadTransationKeys(
frmMain.projectSettings.translationKeys,
frmMain.projectSettings.translatedLanguages)
);
}
But when NotifyLoadTransationKeys() takes a lot of time you'll need to break it up.
Edit:
Calls to Invoke() are often surrounded with if (control.InvokeRequired) , a small optimization. But when you are sure you are on another (than the UI) thread you can skip that.
Related
This question already has answers here:
The calling thread cannot access this object because a different thread owns it
(15 answers)
The calling thread cannot access this object because a different thread owns it.WPF [duplicate]
(6 answers)
Closed 2 years ago.
I have an application which has a C# front end (GUI client), and a C++ back end (business logic). The back end is responsible for requesting progress bar functionality and does this by issuing events which the front-end has observer delegates to respond to and act upon. so events are dispatched and responded to in the main thread.
I would like to spawn a second thread to display and update the progress bar, as the main thread is occupied by the back-end doing its thing. While I can show the progress bar window when supposed to, and correctly hide when finished, it will not respond to updates/increments.
ProgressBarWindow holds the progress bar control (pBar).
ProgressBarWindow is owned by progressBarThread.
public static EventObserver.ProgressBeginEvent pbe = null;
public static EventObserver.ProgressFinishEvent pfe = null;
public static EventObserver.ProgressIncrementEvent pie = null;
public static Thread progressBarThread = null;
static private void InitialiseProgressBarManager()
{
// Setup the progress bar callbacks...
pbe = new EventObserver.ProgressBeginEvent(delegate
(int currentIncrements, int totalIncrements, string message)
{
// Create the thread and progress bar window...
progressBarThread = new Thread(() =>
{
ProgressBarWindow sw = new ProgressBarWindow();
sw.pBar.IsIndeterminate = false;
sw.pBar.Minimum = currentIncrements.Value;
sw.pBar.Maximum = totalIncrements.Value;
sw.pBar.Value = 0;
sw.Show();
pie = new EventObserver.ProgressIncrementEvent(delegate ()
{
sw.pBar.Value++; // The calling thread cannot access this object... see below
});
pfe = new EventObserver.ProgressFinishEvent(delegate ()
{
progressBarThread.Abort();
progressBarThread = null;
});
});
progressBarThread.SetApartmentState(ApartmentState.STA);
progressBarThread.IsBackground = true;
progressBarThread.Start();
});
}
The window shows when expected, and the ProgressIncrementEvent gets raised correctly (it is owned by the thread), however I get an exception when it tries to access the value.
The calling thread cannot access this object because a different thread owns it.
Do I need a mutex or some other lock? I was hoping the scope of the observer delegate would allow the delegate to have mutable access to the thread local ProgressBarWindow even though it is being invoked from the main thread?
I'm not a great C# developer and even less so C# threading so I am a bit stuck about what I should be doing here or even if I can achieve this behaviour. Any help or direction to get this working would be appreciated.
P.S I am using WPF with ProgressBarWindow being defined in XAML.
Try to access the control using the window´s dispatcher:
sw.Dispatcher.BeginInvoke(new Action(() => sw.pBar.Value++));
I'm trying to use a background worker to update a listbox used for a status window in my Form in C#. It doesn't appear to work properly when the addToStausLog() method is called from another class outside of the MyForm class even though I pass an instance of the form to the other class that's calling the addToStatusLog update member. Instead the update doesn't happen until the class member finished and returns back to the MyForm class. Maybe there's a better a approach to creating real-time status windows that will run from any class that MyForm is passed into. I'm new to worker threads, so could someone review and let me know what I might be doing wrong or could improve on.
public MyForm()
{
InitializeComponent();
// Setup background task to update listbox status so UI is unaffected
_lListBoxQue = new List<string>();
bw_listBoxBGWorker = new BackgroundWorker();
bw_listBoxBGWorker.DoWork += (o, args) => LstbxThread_doWork();
bw_listBoxBGWorker.RunWorkerCompleted += (o, args) => LstbxThread_completed();
}
private void LstbxThread_doWork()
{
System.Threading.Thread.Sleep(100);
}
private void LstbxThread_completed()
{
// Update listbox
lstStatusBox.BeginUpdate();
lstStatusBox.Items.Clear(); // clear entries
lstStatusBox.Items.AddRange(_lListBoxQue.ToArray());
lstStatusBox.EndUpdate();
}
public String addToStatusLog(String sMsg)
{
_lListBoxQue.Add(sMsg);
if (_lListBoxQue.Count > _iStatusLogMaxLines) // > max?
_lListBoxQue.RemoveAt(0); // remove top element?
if( !bw_listBoxBGWorker.IsBusy ) // background not busy?
bw_listBoxBGWorker.RunWorkerAsync(); // update listbox in back ground task
System.Threading.Thread.Sleep(100);
return sMsg;
}
This is the member that calls another class which attempts to call the addToStatusLog several times during the process, but the updates to the listbox don't happen until the MyClass(this).updateDB() finishes. I need to see real-time updates as the updateDB() function is running. There has to be a way to make this work, I'm hoping...
private void btnUpdateDB_Click(object sender, EventArgs e)
{
if (_bIsUpdateEventRunning == false ) // is event not busy?
{
_bIsUpdateEventRunning = true;
new MyClass(this).updateDB();
_bIsUpdateEventRunning = false;
}
}
Example of class called to update the form listbox.
Public class MyClass{
private MyForm _pForm;
public MyClass(MyForm pForm){ _pForm= pForm; }
public void updateDB(){
_pForm.addToStatusLog("Hello World");
}
}
Updated Fix w/o background worker:
public String addToStatusLog(String sMsg)
{
_lListBoxQue.Add(sMsg);
if (_lListBoxQue.Count > _iStatusLogMaxLines) // > max?
_lListBoxQue.RemoveAt(0); // remove top element?
lstStatusBox.BeginUpdate();
lstStatusBox.Items.Clear(); // clear entries
lstStatusBox.Items.AddRange(_lListBoxQue.ToArray());
lstStatusBox.EndUpdate();
Application.DoEvents();
return sMsg;
}
Thread.Sleep is not the answer here. What you likely need is Application.DoEvents. This processes all messages currently waiting in the Windows message queue.
Thread.Sleep just tells the thread to go to sleep for the number of milliseconds you specify. If your background worker is running on the UI thread, you're putting the UI thread to sleep and it's effectively comatose. (Important: All Windows forms run on the UI thread.)
There are, of course, alternative designs that involve spinning up separate threads of execution. But these have their own issues, and you should be mindful of them before running blindly down that path.
Creating An MVVM application where application wants to connect to server on a button click. After clicking the button, a thread will be created to connect to the server so that UI doesn't freeze and terminates(TIME OUT is 15 secs). Next time click on the button is creating again new thread to connect to server and terminates.
But first time I want to create a new thread and later I want to reuse that thread(not new) to do the "connect" task if application is not closed and user clicked on the same button.
Is that possible?
Below is the code:
Class ConnectViewModel:BaseViewModel
{
public void ConnectToServer()
{
ConnectButtonEnable = false;
ConnectingServerText = Properties.Resources.TryingToConnectServer;
Thread thread = new Thread(new ThreadStart(connect));
thread.Start();
thread.Join();
}
public void connect()
{
bool bReturn = false;
UInt32 iCommunicationServer;
bReturn = NativeMethods.CommunicateServer(out iCommunicationServer);
if (!bReturn || NativeMethods.ERROR_SUCCESS != iCommunicationServer)
{
ConnectingServerText = Properties.Resources.UnableToConnectToServer;
}
else if (NativeMethods.ERROR_SUCCESS == iCommunicationServer)
{
ConnectingServerText = properties.Resources.SuccessfullyConnectedServer;
}
ConnectButtonEnable = true;
return;
}
}
Due to how the question is phrased I would recommend you to read up on MVVM and async patterns, some examples:
http://msdn.microsoft.com/en-us/magazine/dn605875.aspx
http://richnewman.wordpress.com/2012/12/03/tutorial-asynchronous-programming-async-and-await-for-beginners/
But in general, use async, don't manually create new threads when coding in a GUI-application. If the task shouldn't be callable whilst "running", do test and set via Interlocked.CompareExchange and store away some state.
You use threads for parallel work, not for "waiting on the network".
You can use the TPL to achieve this.
private Task previous = Task.FromResult(true);
public Task Foo()
{
previous = previous.ContinueWith(t =>
{
DoStuff();
});
return previous;
}
By having the operation schedule each operation as the continuation of the previous operation, you ensure that each one doesn't start until the one that came before it finished, while still running all of them in background threads.
Dont worry about creating and managing threads, just use ThreadPool.QueueUserWorkItem instead - its very efficient.
Hey so I am working on something that does the following logic.
Create Parent App, Create Child Process, Have Child process poll data, Send data to Parent App,
Everything is setup fine and is working when I manually Console.WriteLine in child process and I receive that fine in the Parent App.
The problem lies in the fact that the child process is polling input from an xbox controller and then sending that information to the parent app. The problem is that the only way I can think of keeping the child process alive is put in a while loop in Main, once a certain condition is met than close.
However the while loop isn't allowing the process to poll since its just stuck in the loop.
The main caveat is that the polling is done through events so I can't manually poll.
Any ideas on how to keep the passive event type polling to work while keeping the process open?
Here is the setup:
static Battler m_battler = new Battler();
static void Main(string[] args)
{
m_battler = new Battler();
string[] procArgs = (string[])args;
if (procArgs.Length == 0)
{
Console.WriteLine("No Args passed");
Console.Read();
return;
}
parsedArg = procArgs[0].Split('^');
m_battler.NumBattles = Convert.ToInt32(parsedArg[0]);
m_battler has the controller in it and then that uses events to call a function to parse the input and sends it to the parent app, again there is no poll loop its just something like m_xboxController.ProcessedDebugOutput += new XboxController.DebugOutputHandler(Result);
Result parses everything then sends it to the parent app
private void AddHandler()
{
Console.WriteLine("handler");
m_xboxController = new XboxController();
TestDelegate testDel = new TestDelegate(Result);
m_xboxController.ProcessedDebugOutput += new XboxController.DebugOutputHandler(testDel);
threadInit = false;
}
public void Init(int consoleNum, string activeConsole)
{
ThreadStart ts = new ThreadStart(AddHandler);
outputThread = new Thread(ts);
outputThread.Start();
while (threadInit)
{
continue;
}
}
Here is more detail on what is happening
Events are not magical. Depending on how the Battler class or the inner mechanism works, the event handler will be called:
Synchronously
Asynchronously on a separate thread
Asynchronously by invoking on the main thread
The 1st and 2nd option will work with an infinite loop (option 2 will require some thread synchronisation). It appears you believe option 3 is the case.
Before I suggest a solution, could you provide more info on exactly how the event is fired? What makes you think it's dispatched as a message to the main thread and needs to be read from message loop? What is this XboxController class you're using?
I have some trouble with threading in my application. I have a multi-threaded client/server application. I'm also using C# MonoDevelop for Unity3d. Not sure if it makes any difference for the answer. I'll try to explain where my problem is:
Unity works on a single thread. So if i want to instantiate an object which uses the abstract class ScriptableObject from unity, then this must be done on the main thread on which Unity runs.
But my server socket spawns a thread for every connected client, so that incoming data can be processed async. The received data is processed in the OnDataReceived() method (which runs on its own thread)
The problem here is, is that i can't create an instance of a Player object inside the OnDataReceived() thread. Because my Player object inherits from ScriptableObject. Which means this object should be created on the main Unity thread.
But i have no idea how to do that... Is there a way to switch back to the main thread, so i can still create a Player object in the OnDataReceived() method?
.NET already has a concept of a SynchronizationContext, most often used for UI apps where thread affinity is required to invoke operations on UI controls (e.g. in WPF or WinForms). However, even outside a UI app, you can reuse these concepts for a general purpose thread-affinitized work queue.
This sample shows how to use the WPF DispatcherSynchronizationContext (from WindowsBase.dll) in a simple console application, together with the .NET 4.0 task classes (TaskScheduler / Task) to invoke actions originating on child threads back on the main program thread.
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
internal sealed class Program
{
private static void Main(string[] args)
{
int threadCount = 2;
using (ThreadData data = new ThreadData(threadCount))
{
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; ++i)
{
threads[i] = new Thread(DoOperations);
}
foreach (Thread thread in threads)
{
thread.Start(data);
}
Console.WriteLine("Starting...");
// Start and wait here while all work is dispatched.
data.RunDispatcher();
}
// Dispatcher has exited.
Console.WriteLine("Shutdown.");
}
private static void DoOperations(object objData)
{
ThreadData data = (ThreadData)objData;
try
{
// Start scheduling operations from child thread.
for (int i = 0; i < 5; ++i)
{
int t = Thread.CurrentThread.ManagedThreadId;
int n = i;
data.ExecuteTask(() => SayHello(t, n));
}
}
finally
{
// Child thread is done.
data.OnThreadCompleted();
}
}
private static void SayHello(int requestingThreadId, int operationNumber)
{
Console.WriteLine(
"Saying hello from thread {0} ({1}) on thread {2}.",
requestingThreadId,
operationNumber,
Thread.CurrentThread.ManagedThreadId);
}
private sealed class ThreadData : IDisposable
{
private readonly Dispatcher dispatcher;
private readonly TaskScheduler scheduler;
private readonly TaskFactory factory;
private readonly CountdownEvent countdownEvent;
// In this example, we initialize the countdown event with the total number
// of child threads so that we know when all threads are finished scheduling
// work.
public ThreadData(int threadCount)
{
this.dispatcher = Dispatcher.CurrentDispatcher;
SynchronizationContext context =
new DispatcherSynchronizationContext(this.dispatcher);
SynchronizationContext.SetSynchronizationContext(context);
this.scheduler = TaskScheduler.FromCurrentSynchronizationContext();
this.factory = new TaskFactory(this.scheduler);
this.countdownEvent = new CountdownEvent(threadCount);
}
// This method should be called by a child thread when it wants to invoke
// an operation back on the main dispatcher thread. This will block until
// the method is done executing.
public void ExecuteTask(Action action)
{
Task task = this.factory.StartNew(action);
task.Wait();
}
// This method should be called by threads when they are done
// scheduling work.
public void OnThreadCompleted()
{
bool allThreadsFinished = this.countdownEvent.Signal();
if (allThreadsFinished)
{
this.dispatcher.InvokeShutdown();
}
}
// This method should be called by the main thread so that it will begin
// processing the work scheduled by child threads. It will return when
// the dispatcher is shutdown.
public void RunDispatcher()
{
Dispatcher.Run();
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
// Dispose all IDisposable resources.
private void Dispose(bool disposing)
{
if (disposing)
{
this.countdownEvent.Dispose();
}
}
}
}
Sample output:
Starting...
Saying hello from thread 3 (0) on thread 1.
Saying hello from thread 4 (0) on thread 1.
Saying hello from thread 3 (1) on thread 1.
Saying hello from thread 4 (1) on thread 1.
Saying hello from thread 3 (2) on thread 1.
Saying hello from thread 4 (2) on thread 1.
Saying hello from thread 3 (3) on thread 1.
Saying hello from thread 4 (3) on thread 1.
Saying hello from thread 3 (4) on thread 1.
Saying hello from thread 4 (4) on thread 1.
Shutdown.
You could communicate with the original thread through a class such as
class Communicator
{
public static volatile bool CreatePlayer;
}
And in socket code, change the CreatePlayer variable. In the reciever code, check the variable and create a player. After that, set CreatePlayer to false. Similarly with other things. Be careful about manipulating one variable across two threads at the same time - for example, it may be better to have four booleans for CreatePlayer than to have an int NumPlayersToCreate so that both threads aren't trying to constantly access the same data. Of course, you'd have to profile and see. One final thing: make sure the variables changed across both threads are marked as volatile. This makes each thread access the data from main memory rather than keeping it in cache (otherwise, each thread wouldn't notice the data being changed in the other thread's cache).
Yes, this is not the most performant or elegant solution, but it is the simplest. I'm sure someone will suggest a something more involved; if you want, I can do that as well. However, you seem unfamiliar with multithreading, so I thought you'd want something straightforward to get started.