I currently have a application that pings a list of IPs.
The user clicks a button and it continuously pings all IPS for 20 seconds..
What I want to do is click a button to stop this.
I created a function i called "Process" and it calls this process when the button is clicked.
I tried to create a bool value and while loop for when it's false and made the stop button change the bool value to true, but it doesn't seem to stop anything, in fact I can't even close the window until the ping is completed.
My code is below.
private bool _stopLoop;
private void btnPlay_Click(object sender, EventArgs e)
{
Process();
}
private void Process()
{
while (_stopLoop == false)
{
for (int i = 0; i < 20; i++)
{
foreach (DataGridViewRow dataGridView1Row in dataGridView1.Rows)
{
var count = 20;
progressBar1.Value = i * progressBar1.Maximum / count;
Application.DoEvents();
var url = dataGridView1Row.Cells[1].Value.ToString();
int timeout = 500;
Ping ping = new Ping();
PingReply pingreply = ping.Send(url, timeout);
PingReply result = null;
IPStatus status;
result = pingreply;
status = result.Status;
if (status != IPStatus.Success)
{
dataGridView1Row.Cells[0].Style.BackColor = Color.Red;
dataGridView1Row.Cells[0].Value = "Offline";
}
else
{
dataGridView1Row.Cells[0].Style.BackColor = Color.Green;
dataGridView1Row.Cells[0].Value = "Online";
}
}
}
}
}
private void btnStop_Click(object sender, EventArgs e)
{
_stopLoop = true;
}
I am only targeting the direct questions why the loops dont stop. Implementing a background thread or tasks or background worker is a better solution but not the question :)
As in my comment states, you only break out of your "infinite" loop which is the most outer loop.
The two inner loops which run over your IP's ( foreach (DataGridViewRow dataGridView1Row in dataGridView1.Rows){ [...] } as well as your "do it for 20 times" loops for (int i = 0; i < 20; i++){ [...] } need to be broken out of if you want it to stop.
this means you can change them like that:
while (_stopLoop == false)
{
for (int i = 0; i < 20; i++)
{
foreach (DataGridViewRow dataGridView1Row in dataGridView1.Rows)
{
if(_stopLoop)
return; // finish execution and jump out of all loops, or use break to jump into the for loop, but then you need to break out of it as well
/* your ping logic */
}
}
}
If you use async/await your GUI can be responsive and your requests can be concurrent at the same time:
private CancellationTokenSource pingCancellation;
private async void btnPlay_Click(object sender, EventArgs e)
{
const int pingTimeout = 500;
var pingDuration = TimeSpan.FromSeconds(20);
btnPlay.Enabled = false;
dataGridView1.ReadOnly = true;
var entries =
dataGridView1.Rows.Cast<DataGridViewRow>()
.Where(r => !r.IsNewRow)
.Select(row => new { Row = row, Hostname = row.Cells[1].Value.ToString(), Ping = new Ping() })
.ToList();
pingCancellation = new CancellationTokenSource();
pingCancellation.Token.Register(() => entries.ForEach(e => e.Ping.SendAsyncCancel()));
btnStop.Enabled = true;
pingCancellation.CancelAfter(pingDuration);
var finishTime = DateTime.UtcNow.Add(pingDuration);
try
{
while (!pingCancellation.IsCancellationRequested)
{
await Task.WhenAll(entries.Select(async e =>
{
var result = await e.Ping.SendPingAsync(e.Hostname, pingTimeout);
if (result.Status != IPStatus.Success)
{
e.Row.Cells[0].Style.BackColor = Color.Red;
e.Row.Cells[0].Value = "Offline";
}
else
{
e.Row.Cells[0].Style.BackColor = Color.Green;
e.Row.Cells[0].Value = "Online";
}
}).Concat(new[] { Task.Delay(pingTimeout, pingCancellation.Token) /*Rate limiting*/ }));
progressBar1.Value = (int)Math.Min(progressBar1.Maximum * (pingDuration - (finishTime - DateTime.UtcNow)).Ticks / pingDuration.Ticks, progressBar1.Maximum);
}
}
catch (TaskCanceledException)
{
}
btnStop.Enabled = false;
pingCancellation.Dispose();
pingCancellation = null;
foreach (var entry in entries)
{
entry.Ping.Dispose();
}
progressBar1.Value = 0;
dataGridView1.ReadOnly = false;
btnPlay.Enabled = true;
}
private void btnStop_Click(object sender, EventArgs e)
{
if (pingCancellation != null && !pingCancellation.IsCancellationRequested)
{
pingCancellation.Cancel();
}
}
Related
I have the following problem and hope someone can help me.
My basic flow: I want to program any number of devices in parallel using the FTDI D2XX driver and then communicate with them for testing purposes. For this I use two arrays from BackgroundWorker - the first array for programming and the second for testing.
Programming works without any problems. But if I start the BackgroundWorker from the second array to start the test, the connection fails. If I run the complete sequence with only one BackgroundWorker for programming and one BackgroundWorker for testing, the sequence works without problems.
Initialization of BackgroundWorker
private void InitializeBackgoundWorkers()
{
for (var f = 0; f < ftdiDeviceCount; f++)
{
threadArrayProgram[f] = new BackgroundWorker();
threadArrayProgram[f].DoWork += new DoWorkEventHandler(bgr_WorkerStirrerProg_DoWork);
threadArrayProgram[f].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerProgRunWorkerCompleted);
threadArrayProgram[f].WorkerReportsProgress = true;
threadArrayProgram[f].WorkerSupportsCancellation = true;
}
for (var f = 0; f < ftdiDeviceCount; f++)
{
threadArrayTest[f] = new BackgroundWorker();
threadArrayTest[f].DoWork += new DoWorkEventHandler(bgr_WorkerStirrerTest_DoWork);
threadArrayTest[f].RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerTestRunWorkerCompleted);
threadArrayTest[f].WorkerReportsProgress = true;
threadArrayTest[f].WorkerSupportsCancellation = true;
}
}
Aufruf der BackgroundWorker
private void button2_Click_1(object sender, EventArgs e)
{
if (!bStirrerSerached)
{
vSetProgressBarValueRuehrer(1, imaxprogressbar);
vSearchStirrer();
}
if (FtStatus == FTDI.FT_STATUS.FT_OK)
{
//bgr_Worker_Stirrer.RunWorkerAsync();
InitializeBackgoundWorkers();
//---programmieren---//
for (var f = 0; f < /*FilesToProcess*/ftdiDeviceCount; f++)
{
var fileProcessed = false;
while (!fileProcessed)
{
for (var threadNum = 0; threadNum < MaxThreads; threadNum++)
{
if (!threadArrayProgram[threadNum].IsBusy)
{
Console.WriteLine("Starting Thread: {0}", threadNum);
stemp = "Starting Thread: " + threadNum;
File.AppendAllText(slogfile, stemp);
threadArrayProgram[threadNum].RunWorkerAsync(f);
fileProcessed = true;
Thread.Sleep(1000);
break;
}
}
if (!fileProcessed)
{
Thread.Sleep(50);
}
}
}
//---testen---//
for (var f = 0; f < /*FilesToProcess*/ftdiDeviceCount; f++)
{
var fileProcessed = false;
while (!fileProcessed)
{
for (var threadNum = 0; threadNum < MaxThreads; threadNum++)
{
if (!threadArrayTest[threadNum].IsBusy)
{
Console.WriteLine("Starting Thread: {0}", threadNum);
stemp = "Starting Thread: " + threadNum;
File.AppendAllText(slogfile, stemp);
threadArrayTest[threadNum].RunWorkerAsync(f);
fileProcessed = true;
Thread.Sleep(1000);
break;
}
}
if (!fileProcessed)
{
Thread.Sleep(50);
}
}
}
}
button2.Enabled = false;
}
BackgroundWorker
private void bgr_WorkerStirrerProg_DoWork(object sender, DoWorkEventArgs e)
{
try
{
if (FtStatus == FTDI.FT_STATUS.FT_OK)
{
if (ftdiDeviceList != null)
{
//---db werte sammeln---//
cRuehrerProp = new CRuehrerProperties();
cRuehrerProp.SBenutzer = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
cRuehrerProp.SComputername = System.Windows.Forms.SystemInformation.ComputerName.ToString();
//---Rührer programmieren---//
vStirrerProgram((int)e.Argument);
}
}
}
catch (NotSupportedException /*exc*/)
{
}
finally
{
this.Invoke((MethodInvoker)delegate
{
});
}
}
private void bgr_WorkerStirrerTest_DoWork(object sender, DoWorkEventArgs e)
{
try
{
if (!bfinish)
{
while (!bfinish)
{
if (bfinish)
break;
}
}
//---Test starten---//
vStirrerTest((int)e.Argument);
}
catch (NotSupportedException /*exc*/)
{
}
finally
{
this.Invoke((MethodInvoker)delegate
{
button2.Enabled = true;
myFtdiDevice.Close();
});
}
}
Testing method
private void vStirrerTest(int pos)
{
//threadnr
iPosRuehrerGrid = pos;
Console.WriteLine("Thread {0} StirrerTest", pos);
ftStatus = myFtdiDevice.CyclePort();
UInt32 newFtdiDeviceCount = 0;
do
{
// Wait for device to be re-enumerated
// The device will have the same location since it has not been
// physically unplugged, so we will keep trying to open it until it succeeds
ftStatus = myFtdiDevice.OpenByLocation(ftdiDeviceList[iPosRuehrerGrid].LocId);
Console.WriteLine("try to open locid" + ftdiDeviceList[iPosRuehrerGrid].LocId + " on device " + iPosRuehrerGrid);
//ftStatus = myFtdiDevice.OpenByLocation(ftdiDeviceListOrig[iStirrerPosold[iPosRuehrerGrid]].LocId);
Thread.Sleep(1000);
} while (ftStatus != FTDI.FT_STATUS.FT_OK);
// Close the device
myFtdiDevice.Close();
// Re-create our device list
ftStatus = myFtdiDevice.GetNumberOfDevices(ref newFtdiDeviceCount);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
// Wait for a key press
Console.WriteLine("Failed to get number of devices (error " + ftStatus.ToString() + ")");
stemp = "Failed to get number of devices (error " + ftStatus.ToString() + ")";
File.AppendAllText(slogfile, stemp);
return;
}
// Re-populate our device list
ftStatus = myFtdiDevice.GetDeviceList(ftdiDeviceList);
bRepopulateList = true;
vSearchStirrer();
The error occurs in the do loop. If I use only one device - and thus only one thread at a time, it takes an average of 5 runs until the device is opened again. However, if I attach another device and thus have 2 programming and 2 test threads, it does not manage to open the desired device.
I have looked at the DeviceList to make sure it is looking for the right device with the right ID - which it is.
Since I don't have any experience with the Backgrounworker yet, I'm not sure if I haven't forgotten something, which is why this error occurs.
My requirement is to insert item in a queue and process it but the items should be added first and after a while they should be processed (as some other things needs to be set before processing the items. Here is the coding I have done so far.
#region Variables Declarations
private Thread threadTask = null;
ConcurrentQueue<string> concurrentQueue = new ConcurrentQueue<string>();
string currentSeqNo;
string previousSeqNo = "-1";
#endregion
private void test1_Load(object sender, EventArgs e)
{
AddItems();
if (threadTask == null)
{
threadTask = new Thread(Kick);
Thread.Sleep(5000);
threadTask.Start();
}
}
private void AddItems()
{
for (Int64 i = 100000; i < 300000; i++)
{
concurrentQueue.Enqueue(i.ToString());
this.Invoke(new MethodInvoker(delegate()
{
label1.Text = i.ToString();
label1.Update();
}));
}
}
private void Kick()
{
while (true)
{
int recordCountNew = concurrentQueue.Count();
if (recordCountNew != 0)
{
RemoveItems();
}
}
}
private void RemoveItems()
{
string item;
while (concurrentQueue.TryDequeue(out item))
{
this.Invoke(new MethodInvoker(delegate()
{
label2.Text = item;
label2.Update();
}));
currentSeqNo = item; // second time does not start wil 100000
if (previousSeqNo != "-1")
{
if (long.Parse(currentSeqNo) != long.Parse(previousSeqNo) + 1)
{
Reconnect();
}
else
{
//Process item
previousSeqNo = currentSeqNo;
}
}
else
{
//Process item
previousSeqNo = currentSeqNo;
}
}
}
private void Reconnect()
{
currentSeqNo = "";
previousSeqNo = "-1";
string someItem;
while (concurrentQueue.Count > 0)
{
concurrentQueue.TryDequeue(out someItem);
}
this.Invoke(new MethodInvoker(delegate()
{
label1.Text = "";
label2.Text = "";
label1.Update();
label2.Update();
}));
AddItems();
if (threadTask == null)
{
threadTask = new Thread(Kick);
threadTask.Start();
}
}
private void button1_Click_1(object sender, EventArgs e)
{
Reconnect();
}
To reproduce the issue: Run the app and in the middle click on the button. Now the queue should again be started from 100000 but it shows the number somewhere greater than 100000.
Please advise how do I release all the resources to make a fresh start after clicking a button. Though I am setting them to default and also clearing the queue but it still shows the old values in currentSeqNo when 'RemoveItems' method is called.
What you see is a race condition between the Kick thread and the button click handler. When you press the button you execute Reconnect() in it you clean the queue and then call the AddItems() function. But all this time the Kick function tries to Dequeue and so you end up each time with an arbitrary amount of items in it. What you should do is to synchronize between these functions or prevent the Kick from executing while you are adding items.
Couple of comments:
1) You Kick() method have an infinite loop, that too without sleep. Every thread started will keep on running as you didn't have a scope for thread to come out.
You can have a member variable like bKeepRunning with default value as true. Set that variable to false in beginning of Reconnect() function. Something like:
private void Kick()
{
while (bKeepRunning)
{
int recordCountNew = concurrentQueue.Count();
if (recordCountNew != 0)
{
RemoveItems();
}
}
}
Why do you have Thread.Sleep(5000); in test1_Load()? I dont think that is needed.
I made small change in your code, something like:
private void AddItems()
{
for (Int64 i = 100000; i < 300000; i++)
{
concurrentQueue.Enqueue(i.ToString());
this.Invoke(new MethodInvoker(delegate()
{
label1.Text = i.ToString();
label1.Update();
}));
if (i < 100004)
Thread.Sleep(1000);
}
}
private void Kick()
{
while (bKeepRunning)
{
int recordCountNew = concurrentQueue.Count();
if (recordCountNew != 0)
{
RemoveItems();
}
}
}
private void Reconnect()
{
currentSeqNo = "";
previousSeqNo = "-1";
bKeepRunning = false;
threadTask = null;
string someItem;
while (concurrentQueue.Count > 0)
{
concurrentQueue.TryDequeue(out someItem);
}
this.Invoke(new MethodInvoker(delegate()
{
label1.Text = "";
label2.Text = "";
label1.Update();
label2.Update();
}));
Thread.Sleep(2000);
AddItems();
bKeepRunning = true;
if (threadTask == null)
{
threadTask = new Thread(Kick);
threadTask.Start();
}
}
It helped me to see that value is starting from 100000. You can try the same at your end.
Note: I have stopped thread and restarted after clicking on button. Hence i dont see any flaw in your code as such. It just runs fast so that you are not able to realize start values.
You should make UI thread and threadTask thread sync, just use ManualResetEventSlim Signal Construct to, like this:
static ManualResetEventSlim guard = new ManualResetEventSlim(true);
private void button1_Click_1(object sender, EventArgs e)
{
guard.Reset();
Reconnect();
guard.Set();
}
private void RemoveItems()
{
string item;
while (concurrentQueue.TryDequeue(out item))
{
guard.Wait();
//......
}
}
see:
ManualResetEventSlim Class
please help me i wanted to set my pictureBox into visible for only 1 second then hide it again before going to the next loop. here's my code.
private void sampleTxt_Validated(object sender, EventArgs e)
{
words = "AB"
char[] ch = words.ToCharArray();
for (int i = 0; i < ch.Length; i++)
{
if (ch[i] == 'A')
{
a = true;
Application.Idle += imageA;
}
else if (ch[i] == 'B')
{
b = true;
Application.Idle += imageB;
}
}
}
private void imageA(object sender, EventArgs arg)
{
TimeSpan ts;
if(a == true)
{
letterA.Visible = true;
stopWatchA.Start();
ts = stopWatchA.Elapsed;
if (ts.Seconds >= 1)
{
stopwatch();
letterA.Visible = false;
a = false;
}
}
}
private void imageB(object sender, EventArgs arg)
{
TimeSpan ts;
if (b == true)
{
letterB.Visible = true;
stopWatchB.Start();
ts = stopWatchB.Elapsed;
if (ts.Seconds >= 0.5)
{
stopwatch();
letterB.Visible = false;
b = false;
}
}
}
the problem with my code is that it displays both images at the same time.
I want to display the letter "A" image for 1sec first before looping again to display the second image. Is that possible?
You need a loop on letterB, also maybe change the timer from 0.5 to 1.0
Edited question totally for more understanding.
I have a count function, and I have a label who checks the current count
Here is the label
private void currentCountLabel_TextChanged(object sender, EventArgs e)
{
}
How do I make so once the label reaches as example 50, a function starts. like play sound?
//////////////////////////////
Here is the current one that #btc sources, gave me
private void currentCountLabel_Click(object sender, EventArgs e)
{
if (String.Compare(currentCountLabel.Text, "5") == 0)
{
System.Media.SoundPlayer player = new System.Media.SoundPlayer(#"sound.wav");
player.Play();
}
}
But it wont play automaticly, how do I make it to play when it reaches the number?
///////////////////////////////////////////////////////////////////////////////
private void currentCountLabel_TextChanged(object sender, EventArgs e)
{
if (String.Compare(currentCountLabel.Text, "5") == 0)
{
System.Media.SoundPlayer player = new System.Media.SoundPlayer(#"meme.wav");
player.Play();
}
}
private void writeToFile()
{
if (Properties.Settings.Default.OBSToggle)
{
if (Properties.Settings.Default.ReverseOrder)
{
File.WriteAllText(#"Count.txt", String.Format("{0} {1}", Count.ToString(), Message));
}
else
{
File.WriteAllText(#"Count.txt", String.Format("{0} {1}", Message, Count.ToString()));
}
}
private void KeyBoardHook_KeyUp(object sender, KeyEventArgs e)
{
if (Properties.Settings.Default.HotKeyEnabled && e.KeyCode == Properties.Settings.Default.HotKeyIn)
{
if (Properties.Settings.Default.SaveCount)
{
Count = Count + 1;
Properties.Settings.Default.Count = Count;
currentCountLabel.Text = Properties.Settings.Default.Count.ToString();
}
else
{
Count = Count + 1;
currentCountLabel.Text = Count.ToString();
}
Message = messageTextBox.Text;
writeToFile();
e.Handled = true;
}
if (Properties.Settings.Default.HotKeyEnabled && e.KeyCode == Properties.Settings.Default.HotKeyDe && Count != 0)
{
if (Properties.Settings.Default.SaveCount)
{
Count = Count - 1;
Properties.Settings.Default.Count = Count;
currentCountLabel.Text = Properties.Settings.Default.Count.ToString();
}
else
{
Count = Count - 1;
currentCountLabel.Text = Count.ToString();
}
Message = messageTextBox.Text;
writeToFile();
e.Handled = true;
}
}
You need a static variable to hold the current count. Initialized to zero. Then increment it each time the function executes.
Then an if statement to evaluate the count and take whatever action.
I am using background worker for process meantime i need to update progressbar.
I update the progressBar value using backgroundworker.ReportProgress but the values are updated to the user
after the background thread is completed.But i need to show the progress bar update while backgroundworker is running.
my code is
public bool IsClosed()
{
bool profileClosed = false;
for (int i = 0; i < originalEntityList.Count; i++)
{
if (originalEntityList[i] is Core.DatabaseServices.Point)
entityList.RemoveAt(i);
}
CoreApp.ModelSpace.customProgressValue = 0;
CoreApp.ModelSpace.TotalPercentage = OriginalEntityList.Count;
if (!CoreApp.ModelSpace.backgrdWorker.IsBusy)
CoreApp.ModelSpace.backgrdWorker.RunWorkerAsync();
CoreApp.ModelSpace.IndicateProgress(true, new EventArgs());
if (!profileClosed)
UtilitiesLocalization.ShowMessage(UtilitiesLocalization.ProfileNotClosedMessage, UtilitiesLocalization.InvalidProfileTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning);
return profileClosed;
}
private void backgrdWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
if (!checkProfileInvalid)
{
Thread overlapThread = new Thread(new ThreadStart(CheckOverlapEntities));
overlapThread.IsBackground = true;
overlapThread.Start();
overlapThread.Join();
}
}
public static bool CheckOverlapEntities()
{
OverlapedEntities.Clear();
OriginalCollection = new List<Entity>(EntityCollection);
TempCollection = new List<Entity>(EntityCollection);
List<Thread> threadList = new List<Thread>();
for (int id = 0; id < TempCollection.Count; id++)
{
CoreApp.ModelSpace.backgrdWorker.ReportProgress(id+1);
Entity currentEntity = TempCollection[id];
if (currentEntity is PolyLine3d && (currentEntity as PolyLine3d).IsClosed) continue;
Thread tempThread = new Thread(new ParameterizedThreadStart(FindOverlapInParallel));
threadList.Add(tempThread);
tempThread.Start(currentEntity);
if (threadList.Count == MaxThread)
{
for (int i = 0; i < threadList.Count; i++)
{
threadList[i].Join();
if (checkProfileInvalid) break;
}
threadList = new List<Thread>();
}
}
CoreApp.ModelSpace.backgrdWorker.ReportProgress(100);
if (OverlapedEntities.Count > 0)
return true;
return false;
}
void backgrdWorker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
colorProgressBar1.Value = e.ProgressPercentage;
colorProgressBar1.PerformStep();
if (e.ProgressPercentage == colorProgressBar1.Maximum)
colorProgressBar1.Value = 0;
}
Thanks in Advance..