I have a console application that essentially looks like this
class Program
{
static void Main(string[] args)
{
DoStuffService svc = new DoStuffService();
svc.Start();
}
}
class DoStuffService
{
public void Start()
{
Task.Factory.StartNew(() => { LongRunningOperation() });
}
private void LongRunningOperation()
{
// stuff
}
}
What's the best way these days to ensure my console application doesn't exit before LongRunningOperation() is complete, and also allows me a way to be notified in the console application (for logging purposes for instance) that LongRunningOperation() is complete.
call Wait() on the task. For example:
class Program
{
static void Main(string[] args)
{
DoStuffService svc = new DoStuffService();
svc.Start();
// stuff...
svc.DelayTilDone();
}
}
public class DoStuffService
{
Task _t;
public void Start()
{
_t = Task.Factory.StartNew(() => { LongRunningOperation(); });
}
public void DelayTilDone()
{
if (_t==null) return;
_t.Wait();
}
private void LongRunningOperation()
{
System.Threading.Thread.Sleep(6000);
System.Console.WriteLine("LRO done");
}
}
In addition to Cheeso's answer, you'll want to handle Console.CancelKeyPress so that you can display a busy message and set e.Cancel = True.
There's nothing you can do to prevent them from killing the process, but you can at least handle Ctrl+C and Ctrl+Break.
There is a similar thread C# multi-threaded console application - Console quits before threads complete
You can simply return a started task and Wait() or ContinueWith() on it:
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
DoStuffService svc = new DoStuffService();
svc.Start().Wait();//bool res = svc.Start()
Trace.WriteLine("333333333333333");
}
}
public class DoStuffService
{
public Task Start()
{
return Task.Factory.StartNew
(() =>
{
Trace.WriteLine("111111111");
LongRunningOperation(); ;
});
}
private void LongRunningOperation()
{
System.Threading.Thread.Sleep(3000);
Trace.WriteLine("2222222222");
}
}
A task will block the parent thread until completion, if to access its Result property, so:
using System.Diagnostics;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
DoStuffService svc = new DoStuffService();
svc.Start();//bool res = svc.Start()
Trace.WriteLine("333333333333333");
}
}
public class DoStuffService
{
public Task<bool> MyTask;
public bool Start()
{
MyTask = Task.Factory.StartNew<bool>
(() =>
{
Trace.WriteLine("111111111");
return LongRunningOperation();;
});
return MyTask.Result;
}
private bool LongRunningOperation()
{
System.Threading.Thread.Sleep(3000);
Trace.WriteLine("2222222222");
return true;
}
}
Related
I am trying to assign value to my variable in default constructor and Thread Construction. However, I am unable to identify how to solve this issue.
I have created a for loop through which I am assigning my value as well as to Start the Thread.
How can I solve ThreadStart(InitializeServer(I))?
-> Error: Method name expected
What is the other way around for this. ServerInitialization.Start();
-> If I use workerThread.Start() will all individual thread would start? Example Such as Server 1, Server 2?
ServerInitialization.cs
using System;
using System.Threading;
namespace MyApplication
{
public class ServerInitialization
{
public int serverID;
static private int ServersInStore = MainApplication.numofServers;
public ServerInitialization(int serverNum)
{
this.serverID = serverNum;
}
public static void InitializeServer(int sId)
{
ServerInitialization _id = new ServerInitialization(sId);
_id.serverID = sId;
}
public static void AssignServer(int totalServers)
{
for (int i = 0; i<totalServers; ++i)
{
Thread workerThread = new Thread(new ThreadStart(InitializeServer(i)));
ServerInitialization.Start();
}
}
}
MainApplication.cs
using System;
using System.Threading;
namespace MyApplication
{
public class MainApplication
{
public static int numofServers = 0;
static void Main(string[] args)
{
Console.WriteLine("How servers required?");
numofServers = int.Parse(Console.ReadLine());
ServerInitialization.AssignServer(numofServers);
}
}
}
Recreating my C# issue in Java project.
GenerateServer.java
import java.util.Scanner;
public class GenerateServer {
protected static int NumOfServers=4;
public static void main(String[] args) {
// TODO Auto-generated method stub
Server.InitializeServer();
}
}
Server.java
public class Server implements Runnable{
private int serverID;
//private Customer atCounter;
static private int ServersInStor=GenerateServer.NumOfServers;
public Server(int serverID)
{
this.serverID=serverID;
}
public static void InitializeServer()
{
for (int i=0; i<GenerateServer.NumOfServers; ++i)
{
Thread Server = new Thread(new Server(i));
Server.start();
}
}
#Override
public void run() {
// TODO Auto-generated method stub
}
}
Looks like you can just use an anonymous lambda function
Thread workerThread = new Thread(new ThreadStart(() => InitializeServer(i)));
Or in short:
Thread workerThread = new Thread(() => InitializeServer(i));
This question already has answers here:
Why is the console window closing immediately once displayed my output?
(15 answers)
Closed 1 year ago.
I wanted to test if I can trigger an event using method working in a new task.
when I do this:
using System;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
subscriber f = new subscriber();
}
}
class subscriber
{
publisher x;
public subscriber()
{
x = new publisher();
x.ThresholdReached += c_ThresholdReached;
x.method2();
}
static void c_ThresholdReached(object sender, EventArgs e)
{
Console.WriteLine("The threshold was reached.");
}
}
class publisher
{
public event EventHandler ThresholdReached;
public publisher()
{
}
public void method1()
{
OnThresholdReached(EventArgs.Empty);
}
public void method2()
{
Task.Run(() => method1());
}
protected virtual void OnThresholdReached(EventArgs e)
{
EventHandler handler = ThresholdReached;
handler?.Invoke(this, e);
}
}
}
The output is nothing!
However, when I do this:
using System;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
subscriber f = new subscriber();
}
}
class subscriber
{
publisher x;
public subscriber()
{
x = new publisher();
x.ThresholdReached += c_ThresholdReached;
x.method2();
}
static void c_ThresholdReached(object sender, EventArgs e)
{
Console.WriteLine("The threshold was reached.");
}
}
class publisher
{
public event EventHandler ThresholdReached;
public publisher()
{
}
public void method1()
{
OnThresholdReached(EventArgs.Empty);
}
public void method2()
{
//Here is the change
method1();
Task.Run(() => method1());
}
protected virtual void OnThresholdReached(EventArgs e)
{
EventHandler handler = ThresholdReached;
handler?.Invoke(this, e);
}
}
}
the output is this:
The threshold was reached
The threshold was reached
this is strange!
I could not understand why it prints twice.
However, I excepted it will not work with method1 is running in new task, because it will not be working in the same thread
could someone explain why?
and is there a way to communicate a concurrent method with the parent thread?
thanks in advance
As mentioned in comment, your code finishes before the task will run and pring anything. You should modify your code in async manner to await the task to finish
using System;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
static async Task Main(string[] args)
{
subscriber f = new subscriber();
await f.Test();
}
}
class subscriber
{
publisher x;
public subscriber()
{
x = new publisher();
x.ThresholdReached += c_ThresholdReached;
}
public async Task Test()
{
await x.method2();
}
static void c_ThresholdReached(object sender, EventArgs e)
{
Console.WriteLine("The threshold was reached.");
}
}
class publisher
{
public event EventHandler ThresholdReached;
public publisher()
{
}
public void method1()
{
OnThresholdReached(EventArgs.Empty);
}
public async Task method2()
{
await Task.Run(() => method1());
}
protected virtual void OnThresholdReached(EventArgs e)
{
EventHandler handler = ThresholdReached;
handler?.Invoke(this, e);
}
}
}
As for your second snippet, that looks like the Task has time to run and pring while the main thread printing inside method1. Some times it will pring twice (if have enaught of time) or will print once (if Console.Write in main thread will finish before the task will run).
Additional note: please be aware that your event handler will be called not in main thread, but in the thread in which task is executed (typically, this will be a thread from a thread pool)
When you call Task.Run(...), the action inside Run() will be started in new thread.
In your first case you start the new thread with Task.Run(), but the program finishes and exits before it executes that the new thread.
You can prevent the main thread from terminating by adding Console.Read() at the end of Main(). This way you can wait for the second thread to finish.
class Program
{
static void Main(string[] args)
{
subscriber f = new subscriber();
Console.Read();
}
}
In your second case you will get two messages because of this:
public void method2()
{
method1();
Task.Run(() => method1());
}
This time since you are directly calling method1() you will for sure write the message once in the console. Since printing on the console (any IO in general) is relatively slow, the second thread (created by Task.Run()) will have time to execute, and print the message second time.
Another solution is to create the thread manually
public void method2()
{
Thread t1 = new Thread(() => method1());
t1.IsBackground = false;
t1.Start();
}
The program will not exit until all foreground threads have finished. So when you set IsBackground = false;, the program will wait for that thread
I have a console app that instantiates a WeatherClientManager class.
The main thread in the console app requests current weather status in the WeatherClientManager class, but the WeatherClientManager class continuously receives data from a server.
In code:
public static void Main(string [])
{
Program p = new Program();
Task.Run(()=>p.RunLoop());
}
class Program{
WeatherClientManager wcM;
public void RunLoop()
{
wcM = new WeatherClientManager ();
await wcM.InitiateConnection().ConfigureAwait(false);
}
}
class WeatherClientManager
{
public async Task<bool> InitiateConnection()
{
TCPClient tcpClient = new TcpClient(GetTCPDetailsFromConfig())
await tcpClient.ConnectAsync()
CancellationTokenSource cts = new CancellationTokenSource();
if(tcpClient.Connected)
{
Task.Run(()=>ReceiveTask(cts.Token));
Task.Run(()=>SendKeepAlive(cts.Token));
return true;
}
return false;
}
private void ReceiveTask(CancellationToken t)
{
try{
networkStream.Receive(..) // throws exception
}
catch(Exception e)
{
Stop(e);
}
}
private void SendKeepAlive(CancellationToken t)
{
while(!t.IsCancellationRequested)
{
try{
networkStream.Write(..) // throws exception
}
catch(Exception e)
{
Stop(e);
}
}
}
private void Stop(Exception e )
{
log.Error(e);
e.Cancel();
}
}
One of many crap ideas I have is:
Task.Run( () =>
{
while(true)
{
var t1 = Task.Run(()=>ReceiveTask(cts.Token));
var t2= Task.Run(()=>SendKeepAlive(cts.Token));
try{
Tasks.WhenAny(); // should block
}
catch(Exception e)
{
}
finally{
Cleanup();
InitiateConnections();
}
}
}
But I hate the idea of spinning a task to control two sub tasks. My problem is where and how to re-initiate the connection. Any ideas?
EDIT:
I've updated the code such that WeatherClientManager has a OnDisconnectDetected event. So the Program.cs class subscribes like so:
weatherServerManager.OnDisconnectDetected += HandleDisconnectDetection
public async void HandleDisconnectDetection()
{
wsM = new WeatherClientManager ();
wsM.InitiateConnection().ConfigureAwait(false);
}
private void SendKeepAlive(CancellationToken t)
{
while (...)
{
try{}
catch(Exception e)
{
OnDisconnectDetected?.Invoke();
}
}
}
When the handler is invoked by the WeatherClientManager it creates a new task that should continue in a different context. The KeepAlive task should exit then.
Still feels hacky but ideas welcome!
As a general rule, I prefer composition of methods over raising events. In particular, avoid the Task.Run-based fire-and-forget.
In the case of asynchronous sockets, I think it makes sense to give each socket a main loop:
class WeatherClientManager
{
public async Task MainLoop()
{
TCPClient tcpClient = new TcpClient(GetTCPDetailsFromConfig())
await tcpClient.ConnectAsync();
CancellationTokenSource cts = new CancellationTokenSource();
var receiveTask = Task.Run(()=>ReceiveTask(cts.Token));
var keepaliveTask = Task.Run(()=>SendKeepAlive(cts.Token));
await Task.WhenAll(receiveTask, keepaliveTask);
}
}
These can then be composed into the main program's main loop:
class Program
{
public async Task RunLoop()
{
while (true)
{
wcM = new WeatherClientManager();
await wcM.MainLoop();
}
}
}
which in turn is composed into Main:
public static void Main(string [])
{
Program p = new Program();
p.RunLoop().GetAwaiter().GetResult();
}
By avoiding fire-and-forget, you're ensuring that your code will always observe all exceptions. Ignoring tasks is occasionally okay but usually a mistake.
I want my program to wait after below line
frmProgressBarObj = PullMSI.ExtractByMSIName("products.txt", false);
as above method is internally calling thread through StartProcessWithProgress() method . I want that thread to be completed before //code logic -2 line gets executed. At the same time, It should not stop UI update done by frmProgressBar.UpdateProgress(). How do I do this?
namespace NS1
{
public partial class frmMain : Form
{
private void button1_Click(object sender, EventArgs e)
{
frmProgressBar frmProgressBarObj = PullMSI.ExtractByMSIName("products.txt", false);
//code logic - 2
MessageBox.Show("This is executing immediately.
I want to wait until above thread is complete");
}
}
public partial class frmProgressBar : Form
{
public void UpdateProgress(String strTextToDisplayOnProgress)
{
progressBar1.BeginInvoke(
new Action(() =>
{
progressBar1.Value++;
lblFileName.Text = strTextToDisplayOnProgress;
if (progressBar1.Value == progressBar1.Maximum)
{
this.Hide();
}
}));
}
public delegate void DelProgress();
public void StartProcessWithProgress(DelProgress delMethodCode, int maxCount)
{
InitializeProgress(maxCount);
Thread backgroundThread = new Thread(new ThreadStart(delMethodCode));
backgroundThread.Start();
}
}
public static class PullMSI
{
public static frmProgressBar ExtractByMSIName(String strProductFilePath, bool reNameMSI)
{
frmProgressBar frmProgressBar = new frmProgressBar();
frmProgressBar.StartProcessWithProgress(() =>
{
//StreamRader sr declaration and other code
while (!sr.EndOfStream)
{
//logic here
frmProgressBar.UpdateProgress("Copying sr.msiname");
}
}, 2);
return frmProgressBar;
}
}
}
I'm very surprised you haven't worked with any of these before but I would really recommend reading about threading in C# since it's fundamentally important to understand the intricacies and learning the language.
Below are three different ways you can achieve what you want:
1. Using reset events (further reading: https://msdn.microsoft.com/en-us/library/system.threading.manualreseteventslim(v=vs.110).aspx). If your C# version doesn't have the ManualResetEventSlim, replace it with ManualResetEvent and change Wait() with WaitOne()
class LockingWithResetEvents
{
private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false);
public void Test()
{
MethodUsingResetEvents();
}
private void MethodUsingResetEvents()
{
ThreadPool.QueueUserWorkItem(_ => DoSomethingLong());
ThreadPool.QueueUserWorkItem(_ => ShowMessageBox());
}
private void DoSomethingLong()
{
Console.WriteLine("Doing somthing.");
Thread.Sleep(1000);
_resetEvent.Set();
}
private void ShowMessageBox()
{
_resetEvent.WaitOne();
Console.WriteLine("Hello world.");
}
}
2) Using Task Parallel Library (TPL). Further reading: https://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx
class LockingWithTPL
{
public void Test()
{
Task.Factory.StartNew(DoSomethingLong).ContinueWith(result => ShowMessageBox());
}
private void DoSomethingLong()
{
Console.WriteLine("Doing somthing.");
Thread.Sleep(1000);
}
private void ShowMessageBox()
{
Console.WriteLine("Hello world.");
}
}
3) Using Async/Await. Further reading: https://msdn.microsoft.com/en-us/library/hh191443.aspx
class LockingWithAwait
{
public void Test()
{
DoSomething();
}
private async void DoSomething()
{
await Task.Run(() => DoSomethingLong());
ShowMessageBox();
}
private async void DoSomethingLong()
{
Console.WriteLine("Doing somthing.");
Thread.Sleep(10000);
}
private void ShowMessageBox()
{
Console.WriteLine("Hello world.");
}
}
Also good to know: Mutex (https://msdn.microsoft.com/en-us/library/system.threading.mutex(v=vs.110).aspx), Semaphore (https://msdn.microsoft.com/en-us/library/system.threading.semaphore(v=vs.110).aspx), Lock (https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx), SemaphoreSlim (https://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim(v=vs.110).aspx), Monitor (https://msdn.microsoft.com/en-us/library/system.threading.monitor(v=vs.110).aspx) and Interlocked (https://msdn.microsoft.com/en-us/library/system.threading.interlocked(v=vs.110).aspx).
If you're using .NET 4.0 (with VS2012) or above, you can do this quite easily with the Task Parallel Library and async-await:
private async void button1_Click(object sender, EventArgs e)
{
frmProgressBar frmProgressBarObj = await Task.Run(() =>
PullMSI.ExtractByMSIName("products.txt", false));
MessageBox.Show(string.Format("Returned {0}", frmProgressBarObj.ToString());
}
For .NET 4, you'll need to add Microsoft.Bcl.Async.
I was experimenting with the new C# await feature. I made a custom awaiter implementation as follows:
using System;
using System.Runtime.CompilerServices;
using System.Threading;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
T1();
Console.WriteLine("After t1");
}
private static async void T1()
{
CustomAwaitable a = new Sleeper().Sleep();
object r = await a;
Console.WriteLine("sleeper awakes " + r);
}
}
internal class CustomAwaitable
{
private readonly Sleeper m_sleeper;
public CustomAwaitable(Sleeper s)
{
m_sleeper = s;
}
public MyAwaiter GetAwaiter()
{
return new MyAwaiter(m_sleeper);
}
}
internal class Sleeper
{
public ManualResetEvent Handle = new ManualResetEvent(false);
public bool Awake { get; set; }
public int Result
{
get { return Environment.TickCount; }
}
public CustomAwaitable Sleep()
{
new Thread(() =>
{
Thread.Sleep(5000);
Awake = true;
Handle.Set();
}).Start();
Console.WriteLine("begin sleeping " + Result);
return new CustomAwaitable(this);
}
}
internal class MyAwaiter : INotifyCompletion
{
private readonly Sleeper m_sleeper;
public MyAwaiter(Sleeper sleeper)
{
m_sleeper = sleeper;
}
public bool IsCompleted
{
get { return m_sleeper.Awake; }
}
public void OnCompleted(Action continuation)
{
// This works!!
//new Thread(() =>
//{
// m_sleeper.Handle.WaitOne();
// continuation();
//}).Start();
// This doesn't work!!
Action k = () =>
{
m_sleeper.Handle.WaitOne();
continuation();
};
k.BeginInvoke(null, null);
}
public object GetResult()
{
return m_sleeper.Result;
}
}
}
The problem is that, in the OnCompleted method, when I schedule the continuation code execution using BeginInvoke, the GetResult method is never called. But when I create a thread manually to do the same thing, everything works as expected. I know that BeginInvoke uses the thread pool internally, which should work the same way as the thread approach (I know that there is a thread count limit with thread pool, but it is negligible in this case as I am not running anything else).
What are your ideas? Thanks!