All threads doing same job - c#

I want to write network address to my listview, in a range like 192.168.0.0 -192.168.255.255
and I wrote a thread application but when I run this app, all threads are trying to add addresses to listview, does it has a simple solution?
here is my code:
namespace ListNetworkComputers
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
const int step = 16777216;
int threadCount = 1;
private void frmMain_Load(object sender, EventArgs e)
{
ıpAddressControl1.Text = "192.168.0.0";
ıpAddressControl2.Text = "192.168.255.255";
}
private void btnShowPcc_Click(object sender, EventArgs e)
{
threadCount = Convert.ToInt32(nudThreads.Value);
Thread[] threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++)
{
threads[i] = new Thread(new ThreadStart(getPerformance));
threads[i].Name = string.Format(i.ToString());
}
foreach (Thread t in threads)
{
t.Start();
}
}
private void getPerformance()
{
uint startIntAdress, endIntAdress;
startIntAdress = BitConverter.ToUInt32(IPAddress.Parse(ıpAddressControl1.Text).GetAddressBytes(), 0);
endIntAdress = BitConverter.ToUInt32(IPAddress.Parse(ıpAddressControl2.Text).GetAddressBytes(), 0);
for (uint i = startIntAdress; i < endIntAdress; i = i + step)
{
string ipAddress = new IPAddress(BitConverter.GetBytes(i)).ToString();
lbNetworkComputers.Items.Add(ipAddress);
}
}
}
}
And an another problem is, my step method (increaseing adresses as 16777216 ...) isnt working healthy. it goes 192.168.0.0 to 192.168.0.255 but doesnt go on after that.

Because they get same startIntAdress and endIntAdress. Split the range evenly for all threads.
It should be like this:
Thread 1 starts at 192.168.0.0 and checks 32 addresses
Thread 2 at 192.168.0.31 and checks 32,
Thread 3 at 192.168.0.63 and checks 32,
etc

Each thread is running exactly the same code as your loop over the IP addresses is inside the method passed to each thread.
You should pass different start and end addresses into each thread.
You'll also have problems with the threads accessing the UI.
From the code you've posted I'm not sure this really needs to be threaded.

Related

BackgroundWorker - reporting progress with "sub tasks"

A WinForms application with a custom control, LabelProgressBar, which has the ability to display both progress and some descriptive text and/or percentage completion. This is done by calling LabelProgressBar.statusInProgress(string message, int percentageCompletion).
One usage of this is as follows:
private void import_begin(System.Object sender, System.ComponentModel.DoWorkEventArgs args)
{
// first unpack the arguments
System.Object[] arguments = (System.Object[])args.Argument;
System.String filename = (System.String)arguments[0];
System.String why = (System.String)arguments[1];
// tasks:
// 1. read excel file and apply changes to model
// 2. gather changes and format them as XML
// 3. send request to server
// 4. commit/rollback changes
// grab the worker thread so we can report percentage progress
System.ComponentModel.BackgroundWorker worker = (System.ComponentModel.BackgroundWorker)sender;
// now do the work
#region Task1
Controller.Excel excel = new Controller.Excel(filename);
try
{
// the progress of this needs to be tracked
overall_result = excel.import_all(out modified_nodes);
}
catch (InvalidDataExcetpion invDataEx)
{
// deal with it
}
#endregion
worker.ReportProgress(25);
// complete remaining tasks...
}
The event handler for the worker reporting its progress is the following:
private void import_progress(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
Debug.WriteLine("Import percentage completion: " + e.ProgressPercentage);
labelProgressBar1.statusInProgress("Import", e.ProgressPercentage);
}
In short, the import_begin method is broken up into several "tasks". These are broken up into "subtasks". Taking the example of the import_all method:
public Command_Result import_all(out System.Collections.Generic.List<Model.Data_Node> nodes)
{
Command_Result overall_result = Command_Result.OK;
Command_Result this_result;
nodes = new System.Collections.Generic.List<Model.Data_Node>(excel.Workbook.Worksheets.Count);
Model.Data_Node destination;
// the intent is to report the progress of this particular subtask on the basis of how many worksheets have been processed in this for loop
foreach (OfficeOpenXml.ExcelWorksheet worksheet in excel.Workbook.Worksheets)
{
this_result = import_sheet(worksheet.Name, out destination);
nodes.Add(destination);
if (this_result > overall_result)
{
overall_result = this_result;
}
}
return overall_result;
}
The intent is to have this "subtask" report progress on the basis of how many sheets have been processed in the loop. Calculating a percentage for this is a trivial task, but it is not clear to me how this can be reported back to the import_begin method. When this "subtask" is completed, the overall task completion (from the POV of the import_begin method) should be 25%. Similarly for the other tasks. How can this be achieved?
import_begin don't really need to get the update, it can just call the subtasks, while also passing the BackgroundWorker, so the subtasks are responsible to directly report their progress. If "polluting" the subtasks with BackgroundWorker is unacceptable, then create a delegate to call the BackgroundWorker, so your subtasks will then call the delegate instead.
private void mainTask(object sender, DoWorkEventArgs e)
{
var worker = (BackgroundWorker)sender;
var report = new Action<int>(i => worker.ReportProgress(i)); //the delegate
smallTask1Clean(report); //this one pass the delegate
smallTask2(worker); //this one directly call background worker
worker.ReportProgress(100);
}
void smallTask1Clean(Action<int> a)
{
for (int i = 0; i < 20; i++)
{
Thread.Sleep(500);
a(i);
}
}
void smallTask2(BackgroundWorker w)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1000);
w.ReportProgress(i*80/5+20);
}
}
You can also insulate the subtasks from having to know their part in the larger tasks, in this case, the delegate should take two variables, the current internal progress of the subtasks and the total item it needs to process.
private void mainTask(object sender, DoWorkEventArgs e)
{
var worker = (BackgroundWorker)sender;
var preTaskProgress = 0;
var currentTaskTotalPercentage = 0;
var smarterDelegate = new Action<int, int>((current, total) =>
{
worker.ReportProgress(preTaskProgress + (current *currentTaskTotalPercentage/total));
});
currentTaskTotalPercentage = 30; //the following task will in total progressed the main task for 30%
smallTaskClean(smarterDelegate);
preTaskProgress = currentTaskTotalPercentage; //upate the main the progress before starting the next task
currentTaskTotalPercentage = 70; //the following task will in total progressed the main task for 70%
smallTaskClean(smarterDelegate);
worker.ReportProgress(100);
}
void smallTaskClean(Action<int,int> a)
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1500);
a(i,5);
}
}

Access background worker from a different class

I'm separating out logic from one class to another in my Windows Form application. When all in one class, it works fine but I am moving the logic to it's own respective classes now. Having some issues getting at the backgroundWorker from a different class.
I have in class A
public partial class ClassA : Form
BackgroundWorker essentialBgWorker = new BackgroundWorker();
public ClassA()
{
InitializeComponent();
//essentialBgWorker
essentialBgWorker.DoWork += new DoWorkEventHandler(essentialBgWorker_DoWork);
essentialBgWorker.ProgressChanged += new ProgressChangedEventHandler(essentialBgWorker_ProgressChanged);
essentialBgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(essentialBgWorker_RunWorkerCompleted);
essentialBgWorker.WorkerReportsProgress = true;
}
That is a form that has a button which when clicked, copies files to another directory.
private void copyButton_Click(object sender, EventArgs e)
{
clickedButton = ((Button)sender).Name.ToString();
itemsChanged = ((Button)sender).Text.ToString();
essentialBgWorker.RunWorkerAsync();
}
This runs the background worker:
public void essentialBgWorker_DoWork(object sender, DoWorkEventArgs e)
{
string buttonSender = clickedButton; //copyButton, deleteButton, etc.
switch (buttonSender)
{
case "copyButton":
//this is pseudocode - the important part being that this is where I would call the method from the other class
ClassB.copyDocuments();
break;
case "deleteButton":
//this is pseudocode - the important part being that this is where I would call the method from the other class
ClassB.deleteDocuments();
break;
default:
essentialBgWorker.CancelAsync();
break;
}
}
In my other class (ClassB) for this example I have the method that is called when the button is clicked (should be handling the logic).
public void copyDocuments()
{
ClassA classA = new ClassA();
//
//the logic that handles copying the files
//gets the filecount!
//Report to the background worker
int totalFileCount = fileCount;
int total = totalFileCount; //total things being transferred
for (int i = 0; i <= total; i++) //report those numbers
{
System.Threading.Thread.Sleep(100);
int percents = (i * 100) / total;
classA.essentialBgWorker.ReportProgress(percents, i);
//2 arguments:
//1. procenteges (from 0 t0 100) - i do a calcumation
//2. some current value!
}
//Do the copying here
}
I keep having an issue with this line:
classA.essentialBgWorker.ReportProgress(percents, i);
This line worked when it was in ClassA - but once bringing it into ClassB gives an error:
ClassA.essentialBgWorker' is inaccessible due to it's protection level
Just looking for some assistance on the proper way to get it to fire from the other class.
You must add public modifier to essentialBgWorker
public BackgroundWorker essentialBgWorker = new BackgroundWorker();

Firing events in loop are not updating UI in sequence

I was trying to update status on UI for a Long Running Operating. I've created a demo form based application, task it have multiple rows, each row is having days and default values in each column of datagrid is 0, once computation file computes one iteration for one day it will update UI and set 1 for that day.
I am using threading, delegates and events to implement this and it is working as expected if I put Thread.Sleep(100) between two event calls. If I put "Thread.Sleep(100)" inside last nested for loop then it updates UI as expected but as soon as I remove it and run loop without sleep, then it skips some of the columns on UI and directly update last few/random columns, as you can see in attached image link(Image of output of my code without thread sleep) only last column is getting updated.
If I am not mistaken all the events are getting fired in sequence then they should update UI in sequence too but it's not happening and I don't know why. I don't want to do this Sleep thing because I have around 14 calls in actual application for UI status update and it will run under a loop so if It put sleep(100) then it will cost me a lot, is there any way to do it without SLEEP?
Image of output of my code without thread sleep
public class Class1 : IGenerate
{
public event MessageEventHandler OnMessageSending;
public void LongOperationMethod(BindingList<Status> _statusData)
{
if (OnMessageSending != null)
{
MessageEventArgs me = new MessageEventArgs();
/// Loop for 2-3 Weeks
for (; ; ){
/// Loop for 7 day
for (; ; )
{
/// Calculation on everyday
for (int j = 0; j != 1000; ++j)
{
// to do
}
me.weekNo = k;
me.DayNo = i;
OnMessageSending(me);
}
}
me.Message = "Process completed successfully...";
OnMessageSending(me);
}
else
{
throw new ArgumentException("Event hasn`t been rised, so we cannot continue working.");
}
}
}
**UI file:**
<pre><code>
public partial class Form1 : Form
{
BindingList<Status> _statusData = new BindingList<Status>();
delegate void StringParameterDelegate(string value);
Class1 cls = new Class1();
public Form1()
{
InitializeComponent();
labelProgress.Text = "";
}
private void button1_Click_1(object sender, EventArgs e)
{
for (int i = 1; i <= 2; ++i)
{
_statusData.Add(new Status { Week = "Week" + i, Day1 = 0, Day2 = 0, Day3 = 0, Day4 = 0, Day5 = 0, Day6 = 0, Day7 = 0 });
}
dataGridView1.DataSource = _statusData;
}
private void button2_Click(object sender, EventArgs e)
{
Thread t1 = new Thread(() => StartingThread(_statusData));
t1.Start();
}
void StartingThread(BindingList<Status> _statusData)
{
IGenerate generate = new Class1();
generate.OnMessageSending += new MessageEventHandler(generate_OnMessageSending);
generate.LongOperationMethod(_statusData);
}
private void generate_OnMessageSending(MessageEventArgs e)
{
int weekNo = e.weekNo;
int dayNo = e.DayNo;
this.dataGridView1.BeginInvoke(new MethodInvoker(() => dataGridView1.Rows[e.weekNo].Cells[e.DayNo + 1].Value = 1));
this.labelProgress.BeginInvoke(new MethodInvoker(() => this.labelProgress.Text = e.Message));
}
}
</code></pre>
It looks like you are sending the same instance of MessageEventArgs every time, and just updating that one instance on the background thread. This means that your event handler on the UI thread will retrieve the exact same instance of MessageEventArgs that is being updated in the loop! By the time your UI handler gets the MessageEventArgs, its .weekNo and .DayNo properties could well have been modified by the next iteration of the loop, since they are running on separate threads.
To fix this, create a new instance of MessageEventArgs every time you call OnMessageSending().
Relevant snippet:
MessageEventArgs me = new MessageEventArgs();
me.weekNo = k;
me.DayNo = i;
OnMessageSending(me);

Adding percentage text to progressbar C#

I have a method that shows when a process bar is in execution and when is successfully completed.
I worked fine, but I would like to add a percentage showing a 100% if is complete and less if it got stuck some where.
I have made several research online but I could not adapt anything to the solution that I am looking for.
This is my code:
private void progressBar()
{
int i;
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
for (i = 0; i <= 100; i++)
{
progressBar1.Value = i;
}
}
I use the method call on my execution button by calling it with the follow:
progressBar();
Thanks
I have adjust the prograssBar method with the following lines.
The solution works.
Thanks
int percent = (int)(((double)progressBar1.Value / (double)progressBar1.Maximum) * 100);
progressBar1.Refresh();
progressBar1.CreateGraphics().DrawString(percent.ToString() + "%",
new Font("Arial", (float)8.25, FontStyle.Regular),
Brushes.Black,
new PointF(progressBar1.Width / 2 - 10, progressBar1.Height / 2 - 7));
In order to implement the progress in your operation, the operation's length must be calculated first. if it's not possible, you can't show a progress bar for that operation. (maybe only a loading gif)
but if so, There is an interface (IProgress) which can help you implement the progress reports.
First thing you should know, You must do the main task on another thread, and report the progress to the UI Thread. a simple example of this work would be something like this.
Progress.cs
public class Progress<T> : IProgress<T>
{
private readonly Action<T> _progressAction;
public Progress(Action<T> action)
{
_progressAction = action;
}
public void Report(T value)
{
_progressAction?.Invoke(value);
}
}
Your code would be like this, in which the task starts after you click a button named ButtonBase
Progress<int> MyProgressObject { get; set; }
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
MyProgressObject = new Progress<int>(ProgressAction);
ThreadPool.QueueUserWorkItem(TimeConsumingTask);
}
public void TimeConsumingTask(object state)
{
for (int i = 0; i < 100; i++)
{
Thread.Sleep(100);
MyProgressBar.Dispatcher.Invoke(() => ProgressAction(i));
}
}
public void ProgressAction(int progress)
{
MyProgressBar.Value = progress;
}
I know It might look difficult but this is the proper way of doing time consuming tasks and prevent UI block
If you use it as a part of backgroundworker it works perfectly
I added a Label in the middle of the progressbar
And i added last row in my bgw_ProgressChanged method
private void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
p_bar.Value = e.ProgressPercentage;
fnameLbl.Text = e.UserState.ToString();
percentLbl.Text = "%" + (e.ProgressPercentage).ToString();
}
ProgressPercentagevalue comes from the method below
foreach (var item in filebox1)
{
System.IO.File.Move(item, Path.Combine(destdir, Path.GetFileName(item)));
++counter;
int tmp = (int)((counter* 100) / totfiles);
bgw.ReportProgress(tmp, "File transfered : " + Path.GetFileName(item));
Thread.Sleep(100);
}
Totfiles is the number of files that I get from server.
Thread.Sleep(100) let's you see for a short time what is displayed with fnameLbl.Text
int total = ;
int val = ;
double createDivider = total / 100;
int percent = val / createDivider;
this value (percent) is the right percent '%' of total

The calling thread cannot access this object because a different thread owns it

So I am making a simple brick breaking game in c#/wpf. I am running into an issue using timers, I feel like it is probably a simple fix but here is whats happening. Whenever t_Elapsed is fired it attempts to call Update() but when it does its like OMG Im not in the right thread so I cant do that sir. How do I invoke the method from the Game from the proper thread? (And yes I know the code is ugly and has magic numbers but I just kinda chugged it out without putting a lot of effort in. And yes I have zero experience programming games)
public partial class Game : Grid
{
public bool running;
public Paddle p;
public Ball b;
Timer t;
public Game()
{
Width = 500;
Height = 400;
t = new Timer(20);
p = new Paddle();
b = new Ball();
for (int i = 15; i < 300; i += 15)
{
for (int j = 15; j < 455; j += 30)
{
Brick br = new Brick();
br.Margin = new Thickness(j, i, j + 30, i + 15);
Children.Add(br);
}
}
Children.Add(p);
Children.Add(b);
p.Focus();
t.AutoReset = true;
t.Start();
t.Elapsed += new ElapsedEventHandler(t_Elapsed);
}
void t_Elapsed(object sender, ElapsedEventArgs e)
{
if (running)
{
Update();
}
}
void Update()
{
b.Update(); //Error here when Update is called from t_Elapsed event
}
void Begin()
{
running = true;
b.Initiate();
}
}
You should use the DispatcherTimer object instead, it will ensure that the timer events are published to the correct thread.
Timer elapsed events fire on a thread from the thread pool (http://www.albahari.com/threading/part3.aspx#_Timers) and not on the UI thread. Your best approach is to invoke the control's dispatcher through a call like this:
yourControl.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal
, new System.Windows.Threading.DispatcherOperationCallback(delegate
{
// update your control here
return null;
}), null);
The calling thread cannot access this object because a different thread owns it
this.Dispatcher.Invoke((Action)(() =>
{
...// your code here.
}));

Categories