I am working with one application(C# Service), where I need some functionalities like below
Main()
{
App.A();
App.B();
}
App
{
static A()
{
While(true)
{
// Thread logic comes here
Thread.Sleep(60000)
}
}
static B()
{
While(true)
{
// Thread logic comes here
Thread.Sleep(1000)
}
}
}
I need to execute 2 different thread logics in one class
Both is required with different sleep time
How to keep running both the functionalities in this case ? Suggest me any alternative to achieve the same.
Thanks in advance :-)
You either need a Threads / Tasks or use some sort of Timer. There are many ways to do this but you really need to understand what you want to do.
However these might give you food for thought
Disclaimer, You should research these approaches especially tasks, before you attempt this.
Option 1
Task.Run(async () =>
{
while (true)
{
// do the work in the loop
await Task.Delay(60000);
}
});
Option 2
DispatcherTimer _timer = new DispatcherTimer();
void DoWorkTimer()
{
_timer.Interval = TimeSpan.FromMilliseconds(200);
_timer.Tick += _timer_Tick;
_timer.IsEnabled = true;
}
void _timer_Tick(object sender, EventArgs e)
{
// do the work in the loop
}
Related
Here's my situation:
I have a WPF application, where I have a method which takes a lot of time to be completed. I don't want to lose UI responsiveness, so I'd like to call that method in another thread.
I won't paste here my entire code, because it's too long, instead I wrote this short program, which represents well what I'm dealing with:
public void MainWindow()
{
InitializeComponent();
ProcessThread = new Thread(TimeConsumingMethod);
ProcessThread.Name = "ProcessThread";
ProcessThread.Start();
}
public void TimeConsumingMethod()
{
this.Dispatcher.Invoke(() =>
{
MytextBlock.Text = "new text";
MyOtherTextBlock.Text = "Hello";
});
for (int i = 0; i < 50; i++)
{
Debug.WriteLine("Debug line " + i);
}
if (MyRadioButton.IsChecked == false) //????????????????
{
while (true)
{
if (DateTime.Now >= timePicker.Value)
break;
}
}
OtherMethod();
}
Actually, I have two questions for the above code:
1. Everytime I want to access UI controls in my code I have to use this.Dispatcher.Invoke() =>.... Is it the right thing to do? I mean, I have a few places in my method (in my real code) where I check the state of some controls and everytime I need to do his Dispatcher.invoke thing - isn't there a better way to acces these controls?
2. In the code above, there's IF block in the end - in that block I'm checking the state of my RadioButton. Inside of that IF, I have a time consuming code. I cannot just do this:
this.Dispatcher.Invoke(() =>
{
if (MyRadioButton.IsChecked == false) //????????????????
{
while (true)
{
if (DateTime.Now >= timePicker.Value)
break;
}
}
});
That code would tell my UI thread to handle this if block - but I don't want that! That would cause the whole UI to freeze until this IF block gets done. How should I handle this situation?
Well, there are a lot of ways to implement what you are trying to do. One of them might look like this:
public MainWindow() {
InitializeComponent();
Initialize(); //do some intialization
}
private async void Timer_Tick(object sender, EventArgs e) {
if (DateTime.Now >= timePicker.SelectedDate) { //check your condition
timer.Stop(); //probably you need to run it just once
await Task.Run(() => OtherMethod()); //instead of creating thread manually use Thread from ThreadPool
//use async method to avoid blocking UI during long method is running
}
}
private readonly DispatcherTimer timer = new DispatcherTimer(); //create a dispatcher timer that will execute code on UI thread
public void Initialize() {
MytextBlock.Text = "new text";
MyOtherTextBlock.Text = "Hello"; //access UI elements normally
for (var i = 0; i < 50; i++) {
Debug.WriteLine("Debug line " + i);
}
if (MyRadioButton.IsChecked == false)
{
timer.Interval = TimeSpan.FromSeconds(10); // during init setup timer instead of while loop
timer.IsEnabled = true;
timer.Tick += Timer_Tick; //when 10 sec pass, this method is called
timer.Start();
}
}
public void OtherMethod() {
//long running method
Thread.Sleep(1000);
}
I've added some comments, but the main idea is this:
Don't create threads manually, use ThreadPool
Don't loop to wait for something, use timer to periodically check for it
Use async method when you have I/O Tasks
i am trying to use a third party telnet library "active expert" for a basic telnet session.
in my UI code behind i have something like
private async void Button_Click(object sender, RoutedEventArgs e)
{
var ts = new TelnetService();
await ts.DoConnect(node);
}
and my TelnetService looks like this
public class TelnetService
{
private Tcp objSocket = new Tcp();
private NwConstants objConstants = new NwConstants();
public string Responses { get; set; }
private Timer timer1 = new Timer();
public TelnetService()
{
timer1.Elapsed += timer1_Elapsed;
timer1.Interval = 100;
timer1.Start();
}
void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (objSocket.ConnectionState == objConstants.nwSOCKET_CONNSTATE_CONNECTED)
{
if (objSocket.HasData())
{
Responses += objSocket.ReceiveString() + "\r\n";
}
}
}
public Task DoConnect(Node node)
{
return Task.Factory.StartNew(() =>
{
objSocket.Protocol = objConstants.nwSOCKET_PROTOCOL_TELNET;
objSocket.Connect(node.IP, 23);
while (true)
{
if ((Responses == null) || (!Responses.Contains(node.WaitString))) continue;
//do something
Responses = "";
break;
}
});
}
}
there are two important pieces of functionalities.
First in the timer1_Elapsed function which is process that will keeps on ruining and checks if there is data on socket, and if there is, it will append it to a string "Response". and i am using "timer" for it.
Second in the DoConnect function which will check the"Response" string for a certain input. for this i am using async await and Task.
in a nutshell first one accumulating the Response and Second one checking the Response.
Problem is that it looks like the timer code in general and
objSocket.ReceiveString()
line specifically is causing the UI thread to halt for several seconds. which means after clicking the button i cannot move my main form on the screen however the code is running in a separate thread.
i have tried using pure Thread for this but it didn't helped either.
update
instead of timer i am using a method AccumulateResponse
public static void AccumulateResponse()
{
while (true)
{
if (objSocket.ConnectionState == objConstants.nwSOCKET_CONNSTATE_CONNECTED)
{
if (objSocket.HasData())
{
Responses += objSocket.ReceiveString() + "\r\n";
}
}
}
}
and calling it like
var t = new Task(TelnetService.AccumulateResponse);
t.Start();
await TelnetService.DoConnect(node);
still no luck
The DoConnect isn't your problem. It is your Timer Elapsed Event handler.
The timer elapsed event is NOT asynchronous. Only the DoConnect is.
If there is no asynchronous version of ReceiveString() from your third party lib, then use Task.Run there as well inside of an async timer1_elapsed method.
It's clear: For example, imagine a button in my form. When a user clicks on the button, some void method should run after 30 seconds.
There would be a void method DoAfterDelay that takes two input parameter. The first one is the method to do (using delegates), and the other one is the time interval. So I'll have:
public delegate void IVoidDelegate();
static void DoAfterDelay(IVoidDelegate TheMethod, TimeSpan Interval)
{
// *** Some code that will pause the process for "Interval".
TheMethod();
}
So, I just need a piece of code to pause the process for a specific time interval. Heretofore, I used this code to do that:
System.Threading.Thread.Sleep(Interval);
But this code is no good for me, because it stops the whole process and freezes the program. I don't want the program to get stuck in the DoAfterDelay method. That's why the Thread.Sleep is useless.
So could anyone suggest a better way? Of course I've searched about that, but most of the solutions I've found were based on using a timer (like here for example). But using a timer is my last opinion, because the method should run once and using timers makes the program confusing to read. So I'm looking for a better solution if there is. Or maybe I have to use timers?
I guess I have to play with threads, but not sure. So I wonder if anyone could guide me to a solution. Thanks in advance.
Can you use a task?
Task.Factory.StartNew(() =>
{
System.Threading.Thread.Sleep(Interval);
TheMethod();
});
This is where you can use the async await functionality of .Net 4.5
You can use Task.Delay an give the delay in miliseconds.
This is a very clean way. ex:
private async void button1_Click(object sender, EventArgs e)
{
await Task.Delay(5000);
TheMethod();
}
There are several methods of creating thread but of course, it depends on what you are doing.
You can create a thread on the fly like this:
Thread aNewThread = new Thread(
() => OnGoingFunction()
);
aNewThread.Start();
This thread will be running in the background. The function you want to do should have a sleep method to sleep when its done processing. So something like this:
private void OnGoingFunction()
{
//Code....
Thread.Sleep(100); //100 ms, this is in the thead so it will not stop your winForm
//More code....
}
I hope that helps.
Another option is to create the thread whenever you need to process it and not worry about the sleep option. Just create a new thread every time to load the process
You should create a Coroutine
public IEnumerator waitAndRun()
{
// WAIT FOR 3 SEC
yield return new WaitForSeconds(3);
// RUN YOUR CODE HERE ...
}
And call it with:
StartCoroutine(waitAndRun());
DoAfterDelay starts a timer that just runs once, that when it expires it calls your void 'TheMethod'function.
Why would this be messy?
You can specify the exact seconds by using
DateTime runTime = new DateTime();
double waitSeconds = (runTime - DateTime.Now).TotalSeconds;
Task.Factory.StartNew(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(waitSeconds));
YourMethod();
});
runTime => When you want to execute the method.
Here's what you want:
public static void Example1c()
{
Action action = DoSomethingCool;
TimeSpan span = new TimeSpan(0, 0, 0, 5);
ThreadStart start = delegate { RunAfterTimespan(action, span); };
Thread t4 = new Thread(start);
t4.Start();
MessageBox.Show("Thread has been launched");
}
public static void RunAfterTimespan(Action action, TimeSpan span)
{
Thread.Sleep(span);
action();
}
private static void DoSomethingCool()
{
MessageBox.Show("I'm doing something cool");
}
One of the benefits of using Action is that it can be easily modified to pass in parameters. Say you want to be able to pass an integer to DoSomethingCool. Just modify thusly:
public static void Example1c()
{
Action<int> action = DoSomethingCool;
TimeSpan span = new TimeSpan(0, 0, 0, 5);
int number = 10;
ThreadStart start = delegate { RunAfterTimespan(action, span, number); };
Thread t4 = new Thread(start);
t4.Start();
MessageBox.Show("Thread has been launched");
}
public static void RunAfterTimespan(Action<int> action, TimeSpan span, int number)
{
Thread.Sleep(span);
action(number);
}
private static void DoSomethingCool(int number)
{
MessageBox.Show("I'm doing something cool");
}
Very flexible...
Here's a simple extension against Dispatcher that you can use in a non-blocking way.
public static void InvokeAfter(this Dispatcher dispatcher, int milliseconds, Action delayedAction) {
Task.Factory.StartNew(() => {
System.Threading.Thread.Sleep(milliseconds);
dispatcher.Invoke(delayedAction);
});
}
And here's how you use it with a Lambda:
SomeLabel.Dispatcher.InvokeAfter(3000, () => {
SomeLabel.Text = "Hello World";
});
You can also use it with anything that matches Action. Here's an example using a local function...
void doLater(){
SomeLabel.Text = "Hello World";
}
// Pass the action itself, not the result of the action (i.e. don't use parentheses with 'doLater'.)
SomeLabel.Dispatcher.InvokeAfter(3000, doLater);
Note: You can then call it against any dispatcher object where you would normally call Invoke. For safety, I like to invoke it using the dispatcher handling the control I'm updating.
I'm currently making a text based game, but I need the calls to pause for a certain number of milliseconds. I'm looking for something like this:
void InitProgram()
{
WriteToText("Welcome!");
CreatePause(3000); // Pause execution HERE for 3 seconds without locking UI
WriteToText("How are you?"); // Continue
StartTutorial();
}
So like, the method will be called, do its waiting thing, and then return. And when it returns, normal execution is continued.
What can I do for this effect?
You could use a timer:
readonly Timer _timer = new Timer();
void InitProgram()
{
WriteToText("Welcome!");
_timer.Interval = 3000;
_timer.Tick += timer_Tick;
_timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
WriteToText("How are you?"); // Continue
StartTutorial();
_timer.Stop();
}
If you wanted to call this multiple times, just put _timer.Start into it's own method, every time you call it, 3 seconds later whatever is in timer_Tick will happen:
private void StartTimer()
{
_timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
WriteToText("How are you?"); // Continue
StartTutorial();
_timer.Stop();
}
If target framework is 4.0 or higher and IDE is VS2012 or higher, then you can use async/await
private async void Foo()
{
Console.WriteLine("Going to Await");
await Task.Delay(5000);
Console.WriteLine("Done with awaiting");
}
It's pretty simple and straightforward and the biggest advantage is, that your "linear" flow is kept, because the necessary callbacks etc are handled by the compiler automatically.
How about something like this?
Its all pseudo code, I have not tested...
Thread _thread;
void InitProgram()
{
WriteToText("Welcome!");
ThreadStart ts = new ThreadStart(StartThread);
_thread = new Thread(ts);
_thread.Start();
}
private void StartThread()
{
Thread.CurrentThread.Sleep(3000);
this.Invoke(delegate { this.StartTutorial(); });
}
private void StartTutorial()
{
WriteToText("How are you?"); // Continue
//Start tutorial
}
Hahahahhaha! I figured out the answer using possibly the most crazy method available! Check this out, guys!
First, declare global List:
private List<Action> actionList = new List<Action>();
Now, this is what you do in the method you wish to call wait from:
WriteToLog("Hello!");
Action act = delegate() { WriteToLog("How are you?"); }; actionList.Add(act); // Create a new Action out of this method and add it to the action list!
CreatePause(3000); // Call the method with your specified time
void CreatePause(int millisecondsToPause)
{
Action w = delegate() { Thread.Sleep(millisecondsToPause); };
for (int i = 0; i < actionList.Count; i++) // Iterate through each method in the action list that requires attention
{
Action a_Instance = (Action)actionList[i]; // Add a cast to each iteration
AsyncCallback cb = delegate(IAsyncResult ar) { Invoke(a_Instance); w.EndInvoke(ar); }; // Do each method!!!!
w.BeginInvoke(cb, null);
}
actionList.Clear(); // Clear that list!
return; // Return!
}
To be honest, this shouldn't work, but it does.
I am working on a winform application, and my goal is to make a label on my form visible to the user, and three seconds later make the label invisible. The issue here is timing out three seconds. I honestly do not know if this was the correct solution to my problem, but I was able to make this work by creating a new thread, and having the new thread Sleep for three seconds (System.Threading.Thread.Sleep(3000)).
I can't use System.Threading.Thread.Sleep(3000) because this freezes my GUI for 3 seconds!
private void someVoid()
{
lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
Thread sleepThreadStart = new Thread(new ThreadStart(newThread_restProgram));
sleepThreadStart.Start();
// Once three seconds has passed / thread has finished: lbl_authenticationProcess.Visible = false;
}
private void newThread_restProgram()
{
System.Threading.Thread.Sleep(3000);
}
So, back to my original question. How can I determine (from my main thread) when the new thread has completed, meaning three seconds has passed?
I am open to new ideas as well as I'm sure there are many.
Right now, you are blocking the entire UI thread in order to hide a label after 3 seconds. If that's what you want, then just user Thread.Sleep(3000) from within the form. If not, though, then you're best off using a Timer:
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 3000;
timer.Tick += (s, e) => { this.lbl_authenticationProcess.Visible = false; timer.Stop(); }
timer.Start();
After 3 seconds, the label will disappear. While you're waiting for that, though, a user can still interact with your application.
Note that you must use the Forms version of Timer, since its Tick event is raised on the UI thread, allowing direct access to the control. Other timers can work, but interaction with the control would have to be Invoke/BeginInvoked.
Did you try to use Timer
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 3000;
t.Start();
t.Tick += new EventHandler(t_Tick);
void t_Tick(object sender, EventArgs e)
{
label.Visible = false;
}
You really don't need to synchronize anything. You just need a new thread, with a reference to your label. Your code is actually pretty close:
private void someVoid()
{
lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
lbl_authenticationProcess.Visible = true;
Thread sleepThreadStart = new Thread(new ThreadStart(newThread_restProgram));
sleepThreadStart.Start();
}
private void newThread_restProgram()
{
System.Threading.Thread.Sleep(3000);
if (lbl_authenticationProcess.InvokeRequired) {
lbl_authenticationProcess.Invoke(new SimpleCallBack(makeInvisible));
} else {
makeInvisible();
}
}
private void makeInvisible()
{
lbl_authenticationProcess.Visible = false;
}
So, when someVoid() is called, the message on the label is set, the label is made visible. Then a new thread is started with the newThread_restProgram() as the body. The new thread will sleep for 3 seconds (allowing other parts of the program to run), then the sleep ends and the label is made invisible. The new thread ends automatically because it's body method returns.
You can make a method like so:
public void SetLbl(string txt)
{
Invoke((Action)(lbl_authenticationProcess.Text = txt));
}
And you would be able to call it from the second thread, but it invokes on the main thread.
If you're using .NET 3.5 or older, it's kinda a pain:
private void YourMethod()
{
someLabel.BeginInvoke(() =>
{
someLabel.Text = "Something Else";
Thread thread = new Thread(() =>
{
Thread.Sleep(3000);
someLabel.BeginInvoke(() => { someLabel.Visible = false; });
});
thread.Start();
});
}
That should stop you from blocking the UI.
If you're using .NET 4+:
Task.Factory.StartNew(() =>
{
someLabel.BeginInvoke(() => { someLabel.Text = "Something" });
}).ContinueWith(() =>
{
Thread.Sleep(3000);
someLabel.BeginInvoke(() => { someLabel.Visible = false; });
});
If you are willing to download the Async CTP then you could use this really elegant solution which requires the new async and await keywords.1
private void async YourButton_Click(object sender, EventArgs args)
{
// Do authentication stuff here.
lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
await Task.Delay(3000); // TaskEx.Delay in CTP
lbl_authenticationProcess.Visible = false;
}
1Note that the Async CTP uses TaskEx instead of Task.
You can use an AutoResetEvent for your thread synchronization. You set the event to signalled when your secondary thread has woken from it's sleep, so that it can notify your main thread.
That means though that your main thread waits for the other thread to complete.
On that note, you can use SecondThread.Join() to wait for it to complete in your main thread.
You do either of the above, but you don't need to do both.
As suggested in the comments, having a UI thread sleep is not generally a good idea, as it causes unresponsiveness for the user.
However if you do that, you might as well just sleep your main thread and get rid of the extraneous need of the second thread.
I'm not exactly sure this is the right way to do it, but to answer your question, you have to use the Join() function.
public void CallingThread()
{
Thread t = new Thread(myWorkerThread);
t.Join();
}
public void WorkerThread()
{
//Do some stuff
}
You can also add a timeout as parameter to the function, but you don't need that here.