I have a program that is continuously running.
When I start the program, I have a BackgroundWorker (InitialStart.cs):
BackgroundWorker recordingSyncWorker = new BackgroundWorker();
recordingSyncWorker.DoWork += new DoWorkEventHandler(RecordingSyncCheck);
recordingSyncWorker.WorkerSupportsCancellation = false;
recordingSyncWorker.WorkerReportsProgress = false;
recordingSyncWorker.RunWorkerAsync();
void RecordingSyncCheck(object sender, DoWorkEventArgs e)
{
cHandler ch = new cHandler();
Timer theTimer;
int seconds = 1;
if (taskSeconds != null && taskSeconds != "")
seconds = Convert.ToInt32(taskSeconds);
int milliseconds = seconds * 1000;
theTimer = new Timer(10000);
theTimer.Elapsed += new ElapsedEventHandler(ch.SyncMethod);
theTimer.Interval = milliseconds;
theTimer.Enabled = true;
}
And I have two methods in another class (cHandler.cs):
SyncMethod(object source, System.Timers.ElapsedEventArgs e)
{
// random code
}
private string SDCardCheck(object whatever)
{
//more code
}
SDCardCheck gets called thru WCF, so it's like there is another instance of cHandler.cs running. Is there a way for me to pause the BackgroundWorker when I call SDCardCheck?
Don't use a BackgroundWorker just to start a timer. Starting a timer is not a long running operation; it can be done directly from the UI thread.
Your other method can disable the timer to stop it from firing, and then enable it again to allow it to continue firing, in order to effectively pause its execution.
Related
How can I automatically dispose of, and nullify, a timer after it's elapsed?
The sender is a random object with no method; I can't dynamically access the original timer via the EventHandler.
Another function will want to check if this timer is null, or running (and interrupt it).
I could run logic such as:
if (timer != null && timer.Enabled) but I'd rather if (timer != null)
I could also instantiate the variable with a dummy timer, and simply check if this is enabled, but I know if this variable were to suddenly become null, the program would crash.
Should I just use the prior if statement; won't these timers in memory start to add up?
EDIT:
static void Main()
{
Timer timer = null;
timer = new Timer(5000);
timer.Elapsed += (sender, e) => {
var T = (Timer)sender;
T.Dispose();
T = null;
Console.WriteLine(T);
};
timer.Start();
while (true)
{
Console.WriteLine(timer);
System.Threading.Thread.Sleep(1000);
}
}
The sender is a random object with no method
It's not. The object is your timer. You just need to cast it back to its original type:
private void TimerTick(object sender, EventArgs e)
{
var timer = (Timer)sender;
timer.Enabled = false;
}
I have a timer tick event that it's interval set to 10000
private void timer1_Tick(object sender, EventArgs e)
{
Update();
}
In Update i have:
public int Update()
{
counter += 1;
int position = (int)Math.Round((counter / updateTime) * 100);
xpProgressBar1.Text = counter.ToString() + " %";
xpProgressBar1.Position = counter;
if (counter == 10)
{
DownloadingHtml();
ScrollNews();
counter = 0;
}
return position;
}
Then in the backgroundworker do work:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
int position = NewsUpdate();
object param = "report";
backgroundWorker1.ReportProgress(position, param);
}
And the backgroundworker progress event:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
xpProgressBar1.Text = e.ProgressPercentage.ToString() + " %";
xpProgressBar1.Position = e.ProgressPercentage;
if (counter == 10)
{
DownloadingHtml();
ScrollNews();
counter = 0;
}
}
What i want to do in the first step is that the Update method will be called each 10 seconds but through the backgroundworker.
In the second step i want to add to the backgroundworker another method:
public void ScrollNews()
{
label3.Text = SaveOldHtml.HtmlLoadedFileNumber.ToString();
richTextBox1.Clear();
combindedString = string.Join(Environment.NewLine, ListsExtractions.myList);
richTextBox1.SelectAll();
richTextBox1.SelectionAlignment = HorizontalAlignment.Right;
richTextBox1.Text = combindedString;
scrollerText = string.Join(Environment.NewLine, ListsExtractions.myListWithoutLinks);
scroller1.TextToScroll = scrollerText;
if (NewsLevels.newsLevel && NewsLevels.shouldStart)
{
scroller1.Start();
NewsLevels.shouldStart = false;
}
if (NewsLevels.newsLevel == false && NewsLevels.shouldStart)
{
scroller1.Start();
NewsLevels.shouldStart = false;
}
string[] rlines = richTextBox1.Lines;
richTextBox1.SelectionStart = 0;
richTextBox1.SelectionLength = rlines[0].Length;
richTextBox1.SelectionColor = Color.Red;
richTextBox1.Select(rlines[0].Length, rlines[1].Length + 1);
richTextBox1.SelectionColor = Color.Green;
}
The ScrollNews method is being called from the Update method and it's updating richTextBox1 and Scroller1 with text.
And in the end i want to add the last method in Update:
private void DownloadingHtml()
{
using (var webClient = new WebClient())
{
webClient.Encoding = System.Text.Encoding.GetEncoding(1255);
page = webClient.DownloadString("http://rotter.net/scoopscache.html");
}
StreamWriter w = new StreamWriter(#"d:\rotterhtml\rotterscoops.html");
w.Write(page);
w.Close();
page = #"d:\rotterhtml\rotterscoops.html";
listsext.Ext(page);
count++;
}
All this methods i want to be working from the backgroundworker.
In the form1 constructor i did that first it will call the DownloadingHtml method once then call the ScrollNews method once then activate the backgroundworker and then start the timer1.
Seems like you are misusing BackgroundWorker class. It is usually used to perform a single time-consuming action that should not block th UI. All time consuming operations should take place in OnDoWork event that is executed on a separate thread. Report progress is executed on UI thread and is used to update progress bar and other UI elements that show progress.
timer1_Tick is executed on the UI thread and blocks your UI while executing. It's not a good idea to perform any downloading or processing there if you don't want your UI to hang.
You could start TPL Task, Thread or just start BackgroundWorker anew in every timer1_Tick execution. This Task or Thread can then report progress and update current UI state, calling form's thread-safe methods. BackgroundWorker can use it's own ReportProgress mechanism for this purpose.
In case of using separate Task or Thread, each method called from a separate thread should check Form's InvokeRequired and call BeginInvoke to perform thread-safe UI update. This is described well here: beginInvoke, GUI and thread and in many other similar questions.
I have a problem with background worker.
I don't know how exactly to describe it.
Actually its a game and with the background worker ever x milisecs i update the progress bar and check if anyone has lost/won or the time is up.
If someome has win the game ends.
If both players have lost/time is up the game goes to the next round.
The ploblem occurs when both players have lost. The method NextRound in the SetTime method,
runs twice.
Here is the code:
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.SetTime(e.ProgressPercentage);
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(3000);
BackgroundWorker worker = sender as BackgroundWorker;
int tick = ProgLib.maxTime * 10;
for (int i = 1; i <= 100; i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
Thread.Sleep(tick);
worker.ReportProgress(i);
}
}
}
private void SetTime(double k)
{
this.time.Bar1.Value = k;
this.time.Bar2.Value = k;
if (k >= 100 || (Gallery1.hasLost() && Gallery2.hasLost()) || ((Gallery1.isWinner() || Gallery2.isWinner())))
{
if (bw == null)
return;
bw.CancelAsync();
bw.Dispose();
bw = null;
saveData();
ProgLib.isAnyoneWinner(Gallery1.isWinner(), Gallery2.isWinner());
if (ProgLib.gameHasended())
{
gameHasEnded();
}
else
{
next_round();
}
}
}
private void next_round()
{
Thread nextRoundThread = new Thread((Object Send) =>
{
MainThread.Send((Object send) =>
{
Gallery1.hidePanel.Visibility = Visibility.Visible;
Gallery2.hidePanel.Visibility = Visibility.Visible;
ProgLib.nextLetter();//goes to next letter
LetterToPlay1.setLetter(ProgLib.getArrabicLetter(ProgLib.getCurentLetter()));//sets the next letter
LetterToPlay2.setLetter(ProgLib.getArrabicLetter(ProgLib.getCurentLetter()));
}, null);
Thread SoundThread = new Thread((Object send) =>
{
//Here Must Delay enought so the animation stops the hear the bell and the the letter, and then the game starts
Thread.Sleep(1800);
ProgLib.playOtherSound(ProgLib.Sounds.Chimes);//Bell Sound
Thread.Sleep(100);
//ProgLib.PlayLetterSound(ProgLib.getCurentLetter());//Letter Sound
ProgLib.playOtherSound(ProgLib.Sounds.Cat_Yawn);//TestOnly
});
SoundThread.IsBackground = true;
SoundThread.Start();
Thread.Sleep(3000);
MainThread.Send((Object send) =>
{
Gallery1.refresh();//galleries refresh so that the magician hides.
Gallery2.refresh();//
Gallery1.hidePanel.Visibility = Visibility.Hidden;//hide the Big Magician of mistakes
Gallery2.hidePanel.Visibility = Visibility.Hidden;
}, null);
});
nextRoundThread.IsBackground = true;
nextRoundThread.Start();
bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerAsync();
}
There's a threading race in your code. Your worker will call ReportProgress() and immediately iterate the loop. Racing past the CancellationPending property check and falling asleep again.
Your SetTime() method runs later. And calls CancelAsync() but that doesn't have any effect at all since the worker is sleeping. Not until it wakes up again, calls ReportProgress() again, iterates the loop and then sees CancellationPending set to true.
Your SetTime() method will be called again, even though you've already ended the game.
Threading is rife with problems like this. A band-aid is to check for CancellationPending after the Sleep() call. Which works 99.999% of the time. Getting to 100% requires a pretty drastic rewrite that uses proper locking.
at the moment i am using a while (true) loop to do this. I am not very familiar with timers. can someone tell me how i would convert this to work with a timer?
string lyricspath = #"c:\lyrics.txt";
TextReader reader = new StreamReader(lyricspath);
int start = 0;
string[] read = File.ReadAllLines(lyricspath);
string join = String.Join(" ", read);
int number = join.Length;
while (true)
{
Application.DoEvents();
Thread.Sleep(200);
start++;
string str = join.Substring(start, 15);
byte[] bytes = Encoding.BigEndianUnicode.GetBytes(str);
label9.Text = str;
if (start == number - 15)
{
start = 0;
}
}
Why use a timer? I assume this is because you want to have the app remain responsive during such a supposedly long operation. If so cosider using the same sort of code but in a BackgroundWorker.
Also if you do specifically want to use a Timer, beware which one you use; the Systm.Timer invokes its event in a different thread to the one used by the applications hoting form. The Timer in Forms events in the forms thread. You may need to Invoke() the operations in a timer callback that change the label.
Basically, a timer just sits there and counts, and every X milliseconds it "ticks"; it raises an event, which you can subscribe to with a method that does whatever you want done every X milliseconds.
First, all of the variables you will need inside the loop, that come from outside the loop, will need to have "instance scope"; they must be a part of the object that currently has this method, and not "local" variables like they are now.
Then, your current method will need to perform all of the steps prior to the while loop, setting whose "instance" variables I mentioned, and then create and start a Timer. There are several Timers in .NET; the two that would be most useful would likely be either the System.Windows.Forms.Timer or the System.Threading.Timer. This timer will need to be given a handle to the method it should call when it "ticks", and should be told how often to "tick".
Finally, all the code inside the while loop, EXCEPT the calls to Application.DoEvents() and Thread.Sleep(), should be placed in the method that the Timer will run when it "ticks".
Something like this ought to work:
private string[] join;
private int number;
private int start;
private Timer lyricsTimer;
private void StartShowingLyrics()
{
string lyricspath = #"c:\lyrics.txt";
TextReader reader = new StreamReader(lyricspath);
start = 0;
string[] read = File.ReadAllLines(lyricspath);
join = String.Join(" ", read);
number = join.Length;
lyricsTimer = new System.Windows.Forms.Timer();
lyricsTimer.Tick += ShowSingleLine;
lyricsTimer.Interval = 300;
lyricsTimer.Enabled = true;
}
private void ShowSingleLine(object sender, EventArgs args)
{
start++;
string str = join.Substring(start, 15);
byte[] bytes = Encoding.BigEndianUnicode.GetBytes(str);
label9.Text = str;
if (start == number - 15)
{
start = 0;
}
}
This runs every 200 ms. But the suggestion to try Google before asking a question here is a good one.
using Timer = System.Windows.Forms.Timer;
private static readonly Timer MyTimer = new Timer();
...
MyTimer.Tick += MyTimerTask;
MyTimer.Interval = 200; // ms
MyTimer.Enabled = true;
...
private void MyTimerTask(Object o, EventArgs ea)
{
...
}
Simply define a new timer:
Timer timer1 = new Timer();
timer1.Interval = 1; // Change it to any interval you need.
timer1.Tick += new System.EventHandler(this.timer1_Tick);
timer1.Start();
Then define a method that will be called in every timer tick (every [Interval] miliseconds):
private void timer1_Tick(object sender, EventArgs e)
{
Application.DoEvents();
Thread.Sleep(200);
start++;
string str = join.Substring(start, 15);
byte[] bytes = Encoding.BigEndianUnicode.GetBytes(str);
label9.Text = str;
if (start == number - 15)
{
start = 0;
}
}
*Remember to define the variables outside the method so you will be able to access them in the timer1_Tick method.
In a win form application, I have an array of threads which are started like this:
bool stop = false;
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.Length; i++)
threads[i] = new Thread(new ThreadStart(Job));
// How to make sure all threads have exited, when the boolean = false
void Job()
{
while (!stop)
// Do something
}
Now if user press STOP, the boolean value for stop will set to true, so threads exit the Job method one after another. How can I make sure all threads are exited?
NOTE: I need traditional threading for my case and TaskLibrary doesn't fit my scenario.
Use the Join method to check if all threads have stopped.
foreach (var t in threads)
{
t.Join();
}
Have you thought about using BackgroundWorkers instead? You said "traditional threads"..I'm not exactly sure what you mean so I don't know if this is a valid proposal or not, but here it is anyways in case Join() doesn't solve your problem
BackgroundWorker[] workers = new BackgroundWorker[10];
bool allThreadsDone = false;
// initialize BackgroundWorkers
for (int i = 0; i < 10; i++)
{
workers[i] = new BackgroundWorker();
workers[i].WorkerSupportsCancellation = true;
workers[i].RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
workers[i].DoWork += new DoWorkEventHandler(AlgorithmsUI_DoWork);
workers[i].RunWorkerAsync();
}
// thread entry point..DoWork is fired when RunWorkerAsync is called
void AlgorithmsUI_DoWork(object sender, DoWorkEventArgs e)
{
while (!stop)
// do something
}
// this event is fired when the BGW finishes execution
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bool threadsStillRunning = false;
foreach (BackgroundWorker worker in workers)
{
if (worker.IsBusy)
{
threadsStillRunning = true;
break;
}
}
if (!threadsStillRunning)
allThreadsDone = true;
}
protected override OnFormClosing(FormClosingEventArgs e)
{
if (!allThreadsDone)
{
e.Cancel = true;
MessageaBox.Show("Threads still running!");
}
}
This should prevent your form from closing if any threads are still running.
I'm not sure if this is what you're looking for, but here's a simple solution I used back in .NET 3.0 to make sure a large but deterministic number of threads had completed before continuing:
Global:
AutoResetEvent threadPoolComplete = new AutoResetEvent(false);
static int numThreadsToRun;
As you activate the threads:
numThreadsToRun = [number of threads];
[start your threads];
threadPoolComplete.WaitOne();
At the end of each thread's code:
if (Interlocked.Decrement(ref numThreadsToRun) == 0)
{
threadPoolComplete.Set();
}