I have the following code:
void Selection()
{
bool solutionFound = false;
int generation = 0;
int distance = int.MaxValue;
while(!solutionFound)
{
generation++;
for (int i = 0; i < population.Length; i++)
{
population[i].CalcFitness(target);
}
matingPool = new List<DNA>();
for (int i = 0; i < population.Length; i++)
{
int n = (int)(population[i].fitness * 100);
for (int j = 0; j < n; j++)
{
matingPool.Add(population[i]);
}
}
for (int i = 0; i < population.Length; i++)
{
int a = StaticRandom.Instance.Next(matingPool.Count);
int b = StaticRandom.Instance.Next(matingPool.Count);
DNA partnerA = matingPool[a];
DNA partnerB = matingPool[b];
if(partnerA.GetPhrase().Equals(partnerB.GetPhrase()))
{
while(partnerA.GetPhrase().Equals(partnerB.GetPhrase()))
{
a = StaticRandom.Instance.Next(matingPool.Count);
b = StaticRandom.Instance.Next(matingPool.Count);
partnerA = matingPool[a];
partnerB = matingPool[b];
}
}
DNA child = partnerA.Crossover(partnerB);
child.Mutate(mutationRate);
population[i] = child;
ThreadHelperClass.SetText(this, display_lbl, i + ": " + child.GetPhrase());
ThreadHelperClass.SetText(this, gen_lbl, "Generations: " + generation);
int compute = LevenshteinDistance.Compute(target, child.GetPhrase());
if(compute < distance)
{
distance = compute;
ThreadHelperClass.SetText(this, bestPhrase_lbl, "Best Phrase: " + child.GetPhrase());
}
if(child.GetPhrase().Equals(target))
{
solutionFound = true;
break;
}
}
}
}
and the following code
public static class ThreadHelperClass
{
delegate void SetTextCallback(Form f, Control ctrl, string t);
public static void SetText(Form form, Control control, string text)
{
//Invoke requires compares the thread ID of the calling thread
//to the thread ID of the creating thread
//If they are different InvokeRequired sets to true
if (control.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
form.Invoke(d, new Object[] { form, control, text });
}
else
control.Text = text;
}
}
I send Selection to another thread using:
Task.Factory.StartNew(() => Selection(), cToken.Token);
I've already tried to set the ThreadHelper class to use BeginInvoke instead of Invoke and it locks up my UI on the first iteration of the Selection method.
I've also tried to end the task using cToken.Cancel(). This still locks up my UI when the user clicks the stop_btn.
Is there a way I can stop this from happening?
Related
I have a class to load some data from a file and a progress bar form to show the process. My class uses a for loop to load data with a selected buffer size and sets the progress bar value in each loop.
I want to add a cancel and pause button to my form, but when my class starts loading data, the form buttons dont work.
I tried using different threads but they can't have access to same element.
How can I make it so that buttons work when data is loading?
Note: user can select the read type so there are different methods for each type(double,int,byte)
here is my load function:
for (int count = 0; count < (FileSize / LoadBufferSize); count++)
{
if (_check_click == 2)
{
return convertedData;
}
else if(_check_click==1)
{
return new Int16[1];
}
else
{
int j = 0;
for (int i = 0; i < fileContent.Length; i++)
{
try
{
fileContent[i] = br.ReadInt16();
}
catch (EndOfStreamException)
{
loadflag = 1;
contentSize = i;
break;
}
}
for (int k = 0; k < contentSize; k += ReSampleRate)
{
try
{
convertedData[(count * fileContent.Length / ReSampleRate) + j] = fileContent[k];
j++;
}
catch (IndexOutOfRangeException)
{
MessageBox.Show("could not load the file completely");
goto lable;
}
catch
{
MessageBox.Show("something went wrong");
}
}
progress = ((count + 1) * fileContent.Length ) / (FileSize / 100);
barForm.SetBar((int)progress);
}
}
lable:
{
return convertedData;
}
This might be helpful.
public class Form1 : Form
{
private Queue<string> _items = new Queue<string>(new [] { "A", "B", "C" });
private Button _startButton = new Button() { Text = "Start", Top = 8, Left = 4, Height = 24, Width = 100 };
private Button _pauseButton = new Button() { Text = "Pause", Top = 32, Left = 4, Height = 24, Width = 100 };
private bool _paused = false;
public Form1()
{
_startButton.Click += (s, e) => this.Process();
_pauseButton.Click += (s, e) => _paused = true;
this.Controls.Add(_startButton);
this.Controls.Add(_pauseButton);
}
private void Process()
{
if (!_paused && _items.TryDequeue(out string text))
{
Console.WriteLine(text);
this.Invoke(() => this.Process());
}
}
}
The key thing here is that the private void Process() method has a recursive call to itself through the .Invoke method. This keeps running Process so long as there are items in the queue, but it also lets other events occur in the meanwhile, so if someone clicks the Pause button then the Process method will stop running.
There is no for loop. Just a repeating Process method that responds to any changes in state.
I need to compress more folder at same time in different archivie to goes more quikly.
I tried to use a main backgroundworker and from this I did a for cycle to start other backgroundworker for each folder. I notice that the backgroundworker starts all at same time but not works together what is the best way to do a parallel archive?what you suggest?
to create the archive I use the zipforge library
DoWork of the main backgroundworker
if (Directory.Exists(destination))
{
if (MessageBox.Show("", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.No)
{
goto EXIT_UTENTE;
}
else
{
bool finish = false;
int j = 1;
string dest_appoggio = destination;
do
{
dest_appoggio = destination + "_" + j;
if (Directory.Exists(dest_appoggio))
{
j++;
}
else
{
destination = dest_appoggio;
dataprogressiva = data + "_" + j;
finish = true;
}
}
while (finish == false);
}
}
destinationdefault = destination;
var row_list1 = GetDataGridRows(dgwRobot);
int riga = -1;
foreach (DataGridRow single_row1 in row_list1)
{
bool rowselected = false;
single_row1.Dispatcher.Invoke(new Action(() => { rowselected = single_row1.IsSelected; }));
if (rowselected == true)
{
riga = single_row1.GetIndex();
var robotProcessed = false;
while (!robotProcessed)
{
for (var threadNum = 0; threadNum < MaxBackupContemporanei; threadNum++)
{
if (!threadArray[threadNum].IsBusy)
{
threadArray[threadNum].RunWorkerAsync(riga);
robotProcessed = true;
break;
}
}
}
}
Thread.Sleep(500);
}
bool bwTerminati = false;
while (!bwTerminati)
{
for (var threadNum = 0; threadNum < MaxBackupContemporanei; threadNum++)
{
if (threadArray[threadNum].IsBusy)
{
bwTerminati = false;
threadNum = MaxBackupContemporanei;
}
else
{
bwTerminati = true;
}
}
}
I'm trying to simulate a user pressing ctrl down, the main goal would be in a datagridview when I select something programarly (initially) I dont want the user to then change that selection if not just add on to it or subtract, just as if you were to hold ctrl + left mouse click. I have no idea where to even begin. I tried to create a selection change event conbined with logicals but that will cause an infinite loop since we would be selecting one by a user then the code change other and other etc infinitely triggering that event. Please help, I'm sort of new to coding. I also don't know how to determine whether a ctrl key has been pressed, is pressed and being held.
private void selecttionh(object sender, EventArgs e)
{
if (stage == "4A" || stage == "3B" && ModifierKeys.HasFlag(Keys.Control))
{
int nothing = 0;
btnclickercl bt = new btnclickercl();
bt.dataGridView1_SelectionChanged(sender, e, dataGridViewReslist, dataGridViewnewres, nothing);
}
if (stage == "4A" || stage == "3B" && (ModifierKeys & Keys.Control) != Keys.Control)
{
MessageBox.Show("Please Press and hold " + "'ctrl'" + " to continue");
dataGridViewReslist.ClearSelection();
for (int i = 0; i < ResRoomSelections.Count; i++)
{
dataGridViewReslist.Rows[ResRoomSelections[i][0]].Cells[ResRoomSelections[i][1]].Selected = true;
dataGridViewReslist.Rows[ResRoomSelections[i][0]].Cells[(ResRoomSelections[i][1]) + 1].Selected = true;
}
}
else
{
dataGridViewReslist.ClearSelection();
for (int i = 0; i < ResRoomSelections.Count; i++)
{
dataGridViewReslist.Rows[ResRoomSelections[i][0]].Cells[ResRoomSelections[i][1]].Selected = true;
dataGridViewReslist.Rows[ResRoomSelections[i][0]].Cells[(ResRoomSelections[i][1]) + 1].Selected = true;
}
}
}
The way to make this happen is to store the selection state separately, update it when the user clicks a cell, then re-apply it. This prevents the selection from being lost every time they click. If you hook the proper event handlers (mouseup, not click) you can do this without the screen flickering and otherwise being a mess to look at.
Everything you need is in this class, including an extension method SetupToggledSelectionMode(), which is your entry point.
static public class Example
{
static private bool[][] GetSelectionState(DataGridView input)
{
int rowCount = input.Rows.Count;
int columnCount = input.Columns.Count;
var result = new bool[rowCount][];
for (var r = 0; r < rowCount; r++)
{
result[r] = new bool[columnCount];
for (var c = 0; c < columnCount; c++)
{
var cell = input.Rows[r].Cells[c];
result[r][c] = cell.Selected;
}
}
return result;
}
static private void SetSelectionState(DataGridView input, bool[][] selectionState)
{
for (int r = 0; r <= selectionState.GetUpperBound(0); r++)
{
for (int c = 0; c <= selectionState[r].GetUpperBound(0); c++)
{
input.Rows[r].Cells[c].Selected = selectionState[r][c];
}
}
}
static public void SetupToggledSelectionMode(this DataGridView input)
{
bool[][] selectionState = GetSelectionState(input); //This will be stored in a closure due to the lambda expressions below
input.CellMouseUp += (object sender, DataGridViewCellMouseEventArgs e) =>
{
selectionState[e.RowIndex][e.ColumnIndex] = !selectionState[e.RowIndex][e.ColumnIndex];
SetSelectionState(input, selectionState);
};
input.SelectionChanged += (object sender, EventArgs e) =>
{
if (selectionState != null)
{
SetSelectionState(input, selectionState);
}
};
}
}
To use, populate your gridview, set up the initial selection programmatically, and call it like this:
myDataGrid.DataSource = myData;
myDataGrid.Refresh();
myDataGrid.SelectAll();
myDataGrid.SetupToggledSelectionMode();
The SetupToggledSelectionMode() method will register the necessary event handlers and store the selection state of the grid in a closed variable accessible to both handlers. So you won't have to declare anything additional; just call the method.
Thank you for this, this really helped me. all I did was to make it more efficient.Since it would call the Selection change every step of the way, so I got rid of that event completely and only kept the CellMouseup Event.
static private bool[][] GetSelectionState(DataGridView input)
{
int rowCount = input.Rows.Count;
int columnCount = input.Columns.Count;
var result = new List<int[]>();
for (var r = 0; r < rowCount; r++)
{
for (var c = 0; c < columnCount; c++)
{
if(input.Rows[r].Cells[c].Selected==true)
{
result.add(new int[]{r,c});//will keep only the integer of selected items
}
}
}
return result;//this for me was a recycled variable it can be used or recycled from somewhere else
}
private void SetSelectionState(DataGridView input,result)
{
for (int i=0;i<result.Count;i++)
{
input.Rows[result[i][0]].Cells[result[i][1]].Selected = true;
}
}
public void SetupToggledSelectionMode(DataGridView input,result)
{
for (int i=0;i<result.Count;i++)
{
if(result[i].SequenceEqual(new int[] { e.RowIndex, e.ColumnIndex }))
{
result.RemoveAt(i);
continueer = 1;
break;
}
}
if (continueer == 0)
{
ResRoomSelections.Add(new int[] { e.RowIndex, e.ColumnIndex });
}
SetSelectionState(input);
//whatever else you need to do
}
I know there is still a better way to search List but I could not get a lamda search to work so I just used brute force
-Thank you John Wu for all
i have following code and telerik grid my records are 1266880 background worker are hangout for one minutes i try many ways but cannot success anyone know my application does not hang
PopulateUI(List<DataRow> list)
{
this.Invoke(new MethodInvoker(delegate
{
int Count = list.Count;
grdFares.RowCount = Count;
// grdFares.BeginUpdate();
for (int i = 0; i < grdFares.RowCount; i++)
{
grdFares.Rows[i].Cells[COLS.Id].Value = list[i].ItemArray[0].ToStr();
grdFares.Rows[i].Cells[COLS.FROMLOCATION].Value = list[i].ItemArray[7].ToString();
grdFares.Rows[i].Cells[COLS.TOLOCATION].Value = list[i].ItemArray[8].ToString();
grdFares.Rows[i].Cells[COLS.FARE].Value = list[i].ItemArray[4].ToString();
grdFares.Rows[i].Cells[COLS.RowNo].Value = 0;
// grdFares.Rows[i].Cells[COLS.OrignTypeId].Value = list[i].OriginLocationTypeId;
// grdFares.Rows[i].Cells[COLS.DestinationTypeId].Value = list[i].DestinationLocationTypeId;
grdFares.Rows[i].Cells[COLS.VehicleType].Value = list[i].ItemArray[2].ToString();
grdFares.Rows[i].Cells[COLS.VehicleId].Value = list[i].ItemArray[11].ToString();
}
}));
}
I have written a id manager for a xml repository. The repository manages entries in the xml file and assigns unique id (integers) to each entry that is added. The same way databases auto assign new id's to entries added to a table.
The repository will be called asynchronously so I need the id manager to be thread safe. I am using the C# lock statement but it does not seem to help. My unit tests succeed in single threaded execution but fail when run in parallel ( IE: Task ). Specifically they only fail with large sets of parallel tasks above 1000+ and even only then they only fail every other time.
The exception states that it expected 10000 but got 9998. The exception is always the same having to do with 2 missing id that were not registered.
What the heck am I missing?
ID Manager code and unit tests are provided below. The id manager utilizes Linq and is thus not very performance oriented with large sets of id's. Unit Tests TestAsyncRegistration and TestAsyncRandomRegistration are the tests that throw the exceptions.
public class IdManager
{
private List<int> idList = new List<int>();
private List<int> availableList = new List<int>();
private int nextId;
private int bufferCount;
object obj = new object();
public ReadOnlyCollection<int> RegisteredIds
{
get
{
return new ReadOnlyCollection<int>(this.idList);
}
}
public int BufferCount
{
get
{
return this.bufferCount;
}
set
{
if (value < 1)
{
throw new ArgumentOutOfRangeException("value");
}
this.bufferCount = value;
}
}
public IdManager(int bufferCount)
{
this.BufferCount = bufferCount;
this.Reset();
}
public IdManager()
: this(1000)
{
}
public void RegisterId(int id)
{
this.RegisterId(new[] { id });
}
public void Reset()
{
lock (this.obj)
{
this.availableList.Clear();
this.idList.Clear();
for (var i = 0; i < this.bufferCount; i++)
{
this.availableList.Add(i);
}
}
}
public void RegisterId(IEnumerable<int> ids)
{
lock (this.obj)
{
var distinct = ids.Except(this.idList);
this.idList.AddRange(distinct);
this.availableList = this.availableList.Except(this.idList).ToList();
}
}
public int NewId()
{
lock (this.obj)
{
if (this.availableList.Count > 0)
{
var item = this.availableList[0];
this.availableList.RemoveAt(0);
this.idList.Add(item);
return item;
}
var max = this.idList.Max();
for (var i = 1; i < this.bufferCount; i++)
{
this.availableList.Add(max + i);
}
this.availableList = this.availableList.Except(this.idList).ToList();
return this.NewId();
}
}
}
... and the unit test code ...
[TestClass]
public class IdManagerTests
{
[TestMethod]
public void TestSequence()
{
var manager = new IdManager(5);
for (var i = 0; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public void TestBrokenSequence()
{
var manager = new IdManager(5);
manager.RegisterId(1);
Assert.AreEqual(0, manager.NewId());
Assert.AreEqual(2, manager.NewId());
for (var i = 3; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public void TestForwardSequence()
{
var manager = new IdManager(5);
manager.RegisterId(0);
manager.RegisterId(1);
manager.RegisterId(2);
Assert.AreEqual(3, manager.NewId());
Assert.AreEqual(4, manager.NewId());
for (var i = 5; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public void TestBackwardSequence()
{
var manager = new IdManager(5);
manager.RegisterId(2);
manager.RegisterId(1);
manager.RegisterId(0);
Assert.AreEqual(3, manager.NewId());
Assert.AreEqual(4, manager.NewId());
for (var i = 5; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public async Task TestLargeNumbersRegistration()
{
// register a list of id's from 0 to 1000
var list = new List<int>();
for (int i = 0; i < 1000; i++)
{
list.Add(i);
}
var manager = new IdManager(1000);
manager.RegisterId(list);
var taskCount = 10000;
var taskList = new Task[taskCount];
var idValue = 0;
for (int i = 0; i < taskList.Length; i++)
{
manager.RegisterId(idValue++);
}
Assert.AreEqual(taskCount, manager.NewId());
}
[TestMethod]
public async Task TestAsyncRegistration()
{
// register a list of id's from 0 to 1000
var list = new List<int>();
for (int i = 0; i < 1000; i++)
{
list.Add(i);
}
var manager = new IdManager(1000);
manager.RegisterId(list);
var taskCount = 10000;
var taskList = new Task[taskCount];
var idValue = 0;
for (int i = 0; i < taskList.Length; i++)
{
taskList[i] = Task.Factory.StartNew(() => manager.RegisterId(idValue++));
}
Task.WaitAll(taskList);
Assert.AreEqual(taskCount, manager.NewId());
}
[TestMethod]
public async Task TestAsyncRandomRegistration()
{
// register a list of id's from 0 to 1000
var list = new List<int>();
for (int i = 0; i < 1000; i++)
{
list.Add(i);
}
// randomize the order of the id's in the list
var random = new Random((int)DateTime.Now.Ticks);
var randomizedList = from item in list
orderby random.Next()
select item;
var manager = new IdManager(1000);
manager.RegisterId(randomizedList);
var taskCount = 10000;
var taskList = new Task[taskCount];
var idValue = 0;
for (int i = 0; i < taskList.Length; i++)
{
taskList[i] = Task.Factory.StartNew(() => manager.RegisterId(idValue++));
}
Task.WaitAll(taskList);
Assert.AreEqual(taskCount, manager.NewId());
}
}
Your problem is in your test, not the method that you're testing, specifically the snippet:
Task.Factory.StartNew(() => manager.RegisterId(idValue++));
You're calling idValue++ from a bunch of different threads simultaneously. That's not a safe operation to perform. Either increment idValue outside of StartNew and pass in the already incremented value, or use Interlocked.Increment to handle it safely.