I'd like some ideas of how I can make a thread in C# to work as kind of an entity, where it stays "waiting" for me to call some method, and then that method will be executed inside that thread, and not on the thread that called the method.
Let me give an example:
public class ThreadClass
{
public void method1() { do something...}
public void method2() { do something...}
public void method3() { do something...}
} //my class with methods I want to run in another thread than UI, no order specific, when I need it...
public partial class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
//call method1, but it CANNOT RUN IN UI THREAD
}
private void button2_Click(object sender, EventArgs e)
{
//call method2, but it CANNOT RUN IN UI THREAD
}
} //main thread and class
To sum up: My thread has to live "forever", doing nothing, and when I click some button etc, some method will run inside it.
I've tried to use while loop, but I don't know how to call different methods in random moments.
Microsoft's Reactive Framework has an EventLoopScheduler class that does exactly what you want. NuGet System.Reactive.
Try this:
void Main()
{
EventLoopScheduler els = new EventLoopScheduler(); //IDisposable
//starts a new thread and holds it until the instance is disposed.
IDisposable scheduled1 = els.Schedule(() => Method1());
IDisposable scheduled2 = els.Schedule(() => Method2());
IDisposable scheduled3 = els.Schedule(() => Method3());
//Once `Method1` completes `Method2` begins
//Once `Method2` completes `Method3` begins
IDisposable scheduled4 = els.ScheduleAsync((s, ct) => Method4Async(ct));
scheduled1.Dispose(); //Doesn't cancel if started, but unschedules
scheduled2.Dispose(); //Doesn't cancel if started, but unschedules
scheduled3.Dispose(); //Doesn't cancel if started, but unschedules
scheduled4.Dispose(); //Does cancel if started, if not unschedules
els.Dispose(); //Allows thread to end
}
public void Method1() { /* do something... */ }
public void Method2() { /* do something... */ }
public void Method3() { /* do something... */ }
public async Task Method4Async(CancellationToken ct) { /* do something... */ }
Related
I want to start / stop a thread in order not to block the UI using button
public partial class Program_Form : Form
{
readonly BackgroundWorker m_oWorker;
[STAThread]
private void Program_Form_Load(object sender, EventArgs e)
{
// long code here
}
private async void DGW6BtnPrint_Click(object sender, EventArgs e)
{
Work.Printer_ Print = new Work.Printer_();
await Task.Run(() =>
{
Print.Print_File(this, dataGridView6, StatusText, progressBar1,
varriablesStatus);
});
}
public void BTN6PPauza_Click(object sender, EventArgs e)
{
//What i had tried
//_canceller.Dispose();
//_canceller.Cancel();
// varriablesStatus = false;
//thread2.break;
//autoResetEvent.WaitOne();
//thread2.Join();
//_manualResetEvent.Reset();
//thread2.Abort();
//_pauseEvent.Reset();
//varriablesStatus = "Pause";
//Print_Actions();
}
}
Referenced class:
namespace OfficeTools.Work
{
class Printer_
{
public void Print_File(Program_Form callForm, DataGridView DGW,
TextBox Status, ProgressBar Progress, bool varriablesStatus)
{
foreach (DataGridViewRow Row in DGW.Rows)
{
file = DGW.Rows[Row.Index].Cells[4].Value.ToString();
PrintFiles.Print_Word(file);
}
}
}
}
How can I start stop pause resume the thread because nothing worked from what I had tried, I think the problem is from the foreach loop
I never used threads, and I can not find an example similar with mine in order to understand how should I do.
What you are asking implies that you want to use the Thread.Suspend and Thread.Resume methods. Possibly like this:
private volatile Thread _printThread;
private async void DGW6BtnPrint_Click(object sender, EventArgs e)
{
Work.Printer_ Print = new Work.Printer_();
await Task.Run(() =>
{
_printThread = Thread.CurrentThread;
try
{
Print.Print_File(this, dataGridView6, StatusText, progressBar1,
varriablesStatus);
}
finally { _printThread = null; }
});
}
public void BTN6PPauza_Click(object sender, EventArgs e)
{
var printThread = _printThread;
if (printThread != null)
{
if (printThread.ThreadState.HasFlag(ThreadState.Running))
{
printThread.Suspend();
}
else if (printThread.ThreadState.HasFlag(ThreadState.Suspended))
{
printThread.Resume();
}
}
}
The documentation of these two methods includes several cautionary warnings that discourage usage:
Thread.Suspend has been deprecated. Use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources.
Do not use the Suspend and Resume methods to synchronize the activities of threads. You have no way of knowing what code a thread is executing when you suspend it. If you suspend a thread while it holds locks during a security permission evaluation, other threads in the AppDomain might be blocked. If you suspend a thread while it is executing a class constructor, other threads in the AppDomain that attempt to use that class are blocked. Deadlocks can occur very easily.
It's up to you if you want to accept these risks. If you ask me, you shouldn't.
Note: The Suspend and Resume methods are not supported on .NET Core and later platforms. On these platforms they throw a PlatformNotSupportedException exception. You can use them only if you target the .NET Framework platform.
i made this work, i do not know if it is the right way but for the moment it works
public partial class Program_Form : Form
{
readonly BackgroundWorker m_oWorker;
CancellationTokenSource _tokenSource = null;
[STAThread]
private void Program_Form_Load(object sender, EventArgs e)
{
// long code here
}
private async void DGW6BtnPrint_Click(object sender, EventArgs e)
{
_tokenSource = new CancellationTokenSource();
var token = _tokenSource.Token;
Work.Printer_ Print = new Work.Printer_();
await Task.Run(() =>
{
Print.Print_File(this, dataGridView6, StatusText, progressBar1, token);
});
}
public void BTN6PPauza_Click(object sender, EventArgs e)
{
_tokenSource.Cancel();
}
}
Referenced class:
namespace OfficeTools.Work
{
class Printer_
{
public void Print_File(Program_Form callForm, DataGridView DGW, TextBox Status, ProgressBar Progress, CancellationToken Token)
{
foreach (DataGridViewRow Row in DGW.Rows)
{
file = DGW.Rows[Row.Index].Cells[4].Value.ToString();
PrintFiles.Print_Word(file);
if (Token.IsCancellationRequested)
{
try
{
Winword.Quit(ref missing, ref missing, ref missing);
winword = null;
}
catch { }
return;
}
}
}
}
}
Kind regards all
In a small project i am working on i have the neccessity for a component to execute a components shutdown code in the same thread that it was initialized in. However unlike in WPF/Winforms/Web the synchronizationcontext which takes care of this does not work.
My guess is that the lack of a synchronization context is the issue that causes the lack of utilization for ConfigureAwait(true).
Does someone know how to properly implement this?
I read this article but could not make any sense of it yet. Perhaps it was too late yesterday.
Minimal Repro:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleSyncContext
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}");
await SomeBackgroundWorkAsync();
// if this is the same thread as above the question is solved.
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}");
}
private static async Task SomeBackgroundWorkAsync()
{
await Task.Run(() => { });
}
}
}
As you already figured out, console application by default doesn't have synchronization context, so ConfigureAwait has no effect, and continuation after your await SomePageLoad() will run on random thread pool thread. Note that using async main method is essentially equivalent to this:
static async Task AsyncMain() { ... } // your `async Task Main method`
// real Main method generated by compiler
static void RealMain() {
AsyncMain().GetAwaiter().GetResult();
}
In your case you don't need any synchronization context though. What you want is initialize CefSharp on main thread and shutdown CefSharp on main thread. So instead of using async Main - you can do the same as above, but initialize and shutdown Cef outside of async method:
static void Main(string[] args) {
// starting with thread 1
Cef.Initialize(new CefSettings());
try {
AsyncMain(args).GetAwaiter().GetResult();
}
finally {
// we are on main thread here
Cef.Shutdown();
}
}
static async Task AsyncMain(string[] args) {
await SomePageLoad(); // more stuff here
}
Edit: if you insist on using synchronization context then it can be done, but will add a lot of complications for nothing. Out goal is create synchronization context which will run all actions on the same thread. This case be done with simple actions queue, here is basic implementation (don't use it in production, provided as an example only, no exception handling and so on):
class CustomSyncContext : SynchronizationContext {
private readonly BlockingCollection<WorkItem> _queue = new BlockingCollection<WorkItem>(new ConcurrentQueue<WorkItem>());
private readonly Thread _thread;
public CustomSyncContext() {
// start new thread which will handle all callbacks
_thread = new Thread(() => {
// set outselves as current sync context for this thread
SynchronizationContext.SetSynchronizationContext(this);
foreach (var item in _queue.GetConsumingEnumerable()) {
try {
// execute action
item.Action();
}
finally {
// if this action is synchronous, signal the caller
item.Signal?.Set();
}
}
});
_thread.Start();
}
public override void Post(SendOrPostCallback d, object state) {
// Post means acion is asynchronous, just queue and forget
_queue.Add(new WorkItem(() => d(state), null));
}
public override void Send(SendOrPostCallback d, object state) {
// Send means action is synchronous, wait on a single until our thread executes it
using (var signal = new ManualResetEvent(false)) {
_queue.Add(new WorkItem(() => d(state), signal));
signal.WaitOne();
}
}
public void Shutdown() {
// signal thread that no more callbacks are expected
_queue.CompleteAdding();
}
public void WaitForShutdown() {
_thread.Join();
}
private class WorkItem {
public WorkItem(Action action, ManualResetEvent signal) {
Action = action;
Signal = signal;
}
public Action Action { get; }
public ManualResetEvent Signal { get; }
}
}
And your code then becomes:
var ctx = new CustomSyncContext();
ctx.Send(async (_) => {
try {
// starting with thread 1
Cef.Initialize(new CefSettings());
// this method returns on thread 4
await SomePageLoad();
}
finally {
Cef.Shutdown();
// signal the context we are done, so that main thread can unblock
ctx.Shutdown();
Console.WriteLine("done");
}
}, null);
ctx.WaitForShutdown();
Now your code runs on custom synchronization context, and continuation after await SomePageLoad(); will be posted to that synchronization context and executed by our thread (the same thread which inited CefSharp) (no ConfigureAwait(true) is needed, as it's already true by default). Note that we achieved nothing useful - we have one more thread, and our main thread is still blocked waiting for the whole operation to complete (there is no sensible way around that).
Edit 2: here is variation which does not require separate thread, but is not much better:
class CustomSyncContext : SynchronizationContext {
private readonly BlockingCollection<WorkItem> _queue = new BlockingCollection<WorkItem>(new ConcurrentQueue<WorkItem>());
public override void Post(SendOrPostCallback d, object state) {
// Post means acion is asynchronous, just queue and forget
_queue.Add(new WorkItem(() => d(state), null));
}
public override void Send(SendOrPostCallback d, object state) {
// Send means action is synchronous, wait on a single until our thread executes it
using (var signal = new ManualResetEvent(false)) {
_queue.Add(new WorkItem(() => d(state), signal));
signal.WaitOne();
}
}
public void Shutdown() {
// signal thread that no more callbacks are expected
_queue.CompleteAdding();
}
public void Start() {
// now we run the loop on main thread
foreach (var item in _queue.GetConsumingEnumerable()) {
try {
// execute action
item.Action();
}
finally {
// if this action is synchronous, signal the caller
item.Signal?.Set();
}
}
}
private class WorkItem {
public WorkItem(Action action, ManualResetEvent signal) {
Action = action;
Signal = signal;
}
public Action Action { get; }
public ManualResetEvent Signal { get; }
}
}
static async Task Main(string[] args) {
var ctx = new CustomSyncContext();
// set sync context
SynchronizationContext.SetSynchronizationContext(ctx);
// now execute our async stuff
var task = DoStuff().ContinueWith(x => ctx.Shutdown());
// now run the loop of sync context on the main thread.
// but, how do we know when to stop? Something from outside should singal that
// in the case signal is completion of DoStuff task
// note that most of the time main thread is still blocked while waiting for items in queue
ctx.Start();
}
private static async Task DoStuff() {
try {
// starting with thread 1
Cef.Initialize(new CefSettings());
// this method returns on thread 4
await SomePageLoad();
}
finally {
Cef.Shutdown();
// signal the context we are done, so that main thread can unblock
Console.WriteLine("done");
}
}
Your problem is indeed the lack of a Synchronisation context. You can't use ConfigureAwait(true) as this implies that you need to return to the original scheduler/context which does not exist.
Custom implementation
A very simple implementation that ought to do the trick is the one found here. Basically two steps.
Implement a custom synchronization context
public class CustomSynchronizationContext : SynchronizationContext
{
public override void Post(SendOrPostCallback action, object state)
{
SendOrPostCallback actionWrap = (object state2) =>
{
SynchronizationContext.SetSynchronizationContext(new CustomSynchronizationContext());
action.Invoke(state2);
};
var callback = new WaitCallback(actionWrap.Invoke);
ThreadPool.QueueUserWorkItem(callback, state);
}
public override SynchronizationContext CreateCopy()
{
return new CustomSynchronizationContext();
}
public override void Send(SendOrPostCallback d, object state)
{
base.Send(d, state);
}
public override void OperationStarted()
{
base.OperationStarted();
}
public override void OperationCompleted()
{
base.OperationCompleted();
}
}
Initaliaze it and use it
static void Main()
{
var context = new CustomSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(context);
AsyncEx library
You can also use the AsyncEx library
private static void Main(string[] args)
{
AsyncContext.Run(() => AsyncMethod(args));
}
static async void AsyncMethod(string[] args)
{
await something().ConfigureAwait(true);
}
My constructor besides other things call another method DoWork
public MyTask(TaskAction action)
{
DoWork(action);
}
DoWork method goes to another method Calc(2)
private void Calc (int 2){
... calc and save result into file
}
How can I alert MyTask that Calc is done and let MyTask to continue further.
P.S. I could read hdd every few secs in order to see whether file with result is save and based on that continue further, but I assume that there is better way.
BackgroundWorker class allows you to easily manage your async work.
BackgroundWorker _worker = new BackgroundWorker();
public Cnt()
{
InitializeComponent();
_worker.DoWork += WorkerOnDoWork;
_worker.RunWorkerCompleted += WorkerOnRunWorkerCompleted;
//start your work
_worker.RunWorkerAsync();
}
private void WorkerOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Worker completed event
}
private void WorkerOnDoWork(object sender, DoWorkEventArgs e)
{
//Do
}
There are many ways to do this.The latest recommended is using tasks
Task taskA = new Task(() => { Console.WriteLine("Task A started"); });
taskA.ContinueWith((ss) => { Console.WriteLine("Task A finished"); });
taskA.Start();
http://msdn.microsoft.com/en-us/library/ee372288(v=vs.110).aspx
This way you can block the current thread if you want.
Another way is the BackGroundWorker Class
Also, you can use a custom callback like this
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DoWorkA(DoWorkFinished);
Console.Read();
}
private static void DoWorkA(Action whatToDoWhenFinished)
{
Console.WriteLine("Doing something");
whatToDoWhenFinished();
}
private static void DoWorkFinished()
{
Console.WriteLine("Doing something Else");
}
}
}
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.
I am using
System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5));
I want to call the following method from the main thread every time the call to MyMethod is completed:
UpdateGui()
{
}
How do I do that?
Thanks!
Keep a global counter of work items queued and an object to protect it:
int runningTasks = 0;
object locker = new object();
Every time a task is added increment the counter:
lock(locker) runningTasks++;
System.Threading.ThreadPool.QueueUserWorkItem(x => MyMethod(param1, param2, param3, param4, param5));
At the end of MyMethod decrement the counter and signal the main thread:
lock(locker)
{
runningTasks--;
Monitor.Pulse(locker);
}
In the main thread (assuming this is not the GUI thread!):
lock(locker)
{
while(runningTasks > 0)
{
Monitor.Wait(locker);
UpdateGUI();
}
}
This way you also have a barrier to wait for all pending tasks to finish.
In case you don't want to wait, just skip the main thread completely and call UpdateGUI to forward updates to the GUI thread when MyMethod finishes.
Note that inside MyMethod you should have some form of Dispatcher.BeginInvoke (WPF) or Control.BeginInvoke (WinForms) otherwise you cannot update the GUI safely!
Post a call to the updategui method back to the sync context for the ui thread at the end of the threadpool method...
Example:
private SynchronizationContext _syncContext = null;
public Form1()
{
InitializeComponent();
//get hold of the sync context
_syncContext = SynchronizationContext.Current;
}
private void Form1_Load(object sender, EventArgs e)
{
//queue a call to MyMethod on a threadpool thread
ThreadPool.QueueUserWorkItem(x => MyMethod());
}
private void MyMethod()
{
//do work...
//before exiting, call UpdateGui on the gui thread
_syncContext.Post(
new SendOrPostCallback(
delegate(object state)
{
UpdateGui();
}), null);
}
private void UpdateGui()
{
MessageBox.Show("hello from the GUI thread");
}
Assuming that MyMethod is a synchronous method, invoked inside QueueUserWorkItem in order to make it execute asynchronously, the following approach may be used:
ThreadPool.QueueUserWorkItem(x =>
{
MyMethod(param1, param2, param3, param4, param5);
UpdateGui();
});
Note that you have to update GUI elements inside UpdateGui() by calling Invoke/BeginInvoke.
This may keep the client cleaner letting the class handle the cross threading switching mechanism. This way the GUI consumes your class in normal fashion.
public partial class Form1 : Form
{
private ExampleController.MyController controller;
public Form1()
{
InitializeComponent();
controller = new ExampleController.MyController((ISynchronizeInvoke) this);
controller.Finished += controller_Finished;
}
void controller_Finished(string returnValue)
{
label1.Text = returnValue;
}
private void button1_Click(object sender, EventArgs e)
{
controller.SubmitTask("Do It");
}
}
The GUI form subscribes to events of the class unaware they are mulch-threaded.
public class MyController
{
private ISynchronizeInvoke _syn;
public MyController(ISynchronizeInvoke syn) { _syn = syn; }
public event FinishedTasksHandler Finished;
public void SubmitTask(string someValue)
{
System.Threading.ThreadPool.QueueUserWorkItem(state => submitTask(someValue));
}
private void submitTask(string someValue)
{
someValue = someValue + " " + DateTime.Now.ToString();
System.Threading.Thread.Sleep(5000);
//Finished(someValue); This causes cross threading error if called like this.
if (Finished != null)
{
if (_syn.InvokeRequired)
{
_syn.Invoke(Finished, new object[] { someValue });
}
else
{
Finished(someValue);
}
}
}
}