Forgive me if this is simple. I come from the Embedded RToS world and have learnt c# for just for the purpose of test equipment for production. I think I have solved all the obvious issues already, just the tasks are not acting as expected.
I have a test jig with 10 serial ports and other things attached and a very basic windows forms UI with 10 list box's that need to all run simultaneously. I have cut the code down to just what is needed for the demo of the problem (no serial ports etc)
I am unable to get 10 listbox's (or textboxs) to update from 10 tasks properly. I can easily do one at a time, even 5 works, but 10 and it does not work.
I was getting exception out of range as it somehow gets passed a 10, but I only pass 0-9 so I reduced the task count to 9 for now until I understand the fundamental issue(s).
private void buttonStart_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() => PTT.ProductionTest());
}
This is the task from the PTT class, it will manage and monitor the 10 tasks so the UI is still responsive
public static void ProductionTest()
{
//Somewhere to store the tasks
List<Task> TestSlotTasks = new List<Task>();
//Create the tasks for each of the test slots
for (int i = 0; i != 9; ++i)
{
TestSlotTasks.Add(Task.Factory.StartNew(() => new PTT().TestSlot(i)));
Program.ListBoxAddLine(string.Format("CALL[{0}]: task start/stop test", i), System.Drawing.Color.LawnGreen, i);
}
Task.WaitAll(TestSlotTasks.ToArray());
}
This is supposed to be a non static program so I can create multiple instances (so I can run it many times without issue, that is my intention anyway, right?)
private void TestSlot(int slot)
{
for (var z = 0; z != 10; ++z)
{
Program.ListBoxAddLine(string.Format("PTT[{0}]: task start/stop test", slot), System.Drawing.Color.LawnGreen, slot);
}
}
This is the invoke method i use to update the listBox. The list box is in a generic list something like this
//ListBoxs.Add(listBoxSlot1); //Done for each of the 10 list box's to put in a list
//This is the method that will add a line to the main text box and to the log file
public static void ListBoxAddLine(string TextToAdd, System.Drawing.Color textColor, int slot)
{
//Update the list box on the main screen
if (mainForm != null)
{
if (FormPTT.ListBoxs[slot].InvokeRequired)
{
FormPTT.ListBoxs[slot].Invoke((MethodInvoker)delegate ()
{
FormPTT.ListBoxs[slot].ForeColor = textColor;
FormPTT.ListBoxs[slot].TopIndex = FormPTT.ListBoxs[slot].Items.Add(TextToAdd);
});
}
else
{
FormPTT.ListBoxs[slot].ForeColor = textColor;
FormPTT.ListBoxs[slot].TopIndex = FormPTT.ListBoxs[slot].Items.Add(TextToAdd);
}
}
}
The output I get is pretty random if i go above 5 or 6 list box's for this example.
Using the above code, I get this
output in the list box's, ignore the other stuff
So its all ok up until slot 8, its shows the Call[7] task start/stop but nothing from the task call and 9 and 10 are ok, but I dont call it 10 times, so how is 10 getting updated? I dont pass 10? and where is 8's PTT[7]... output?
I assume I am just not understanding a few things about tasks...
Related
I made a SUDOKU solver. When is solve a number it should be written to the screen but it's happen only when the solver is done. Why only then the screen is refreshing when it is done?
ii is the number, jj is the row, ll is the column
private void MainForm_Load(object sender, EventArgs e)
{
...
Thread tr2 = new Thread(adatbszal);
tr2.Start();
}
private void adatbszal()
{
while (fut)
{
Thread.Sleep(10);
if (adat[jj, ll] != 0)
{
SetText(jj, ll, adat[jj, ll].ToString());
}
else
{
SetText(jj, ll, "");
}
}
}
private void SetText(int i, int j, string adat2)
{
if (adatB[i,j].InvokeRequired)
{
valami d = new valami(SetText);
Invoke(d, new object[] { i, j, adat2 });
}
else
{
adatB[i, j].Text = adat2;
}
}
...
Thread th = new Thread(solver);
th.Start();
full project: https://drive.google.com/file/d/1sZTA4Ledfwl3romBY2UTvUoU9MZfY35g/view?usp=sharing
I would suggest putting a breakpoint on Invoke(d, new object[] { i, j, adat2 }); to verify that it is being reached, and when it is, add a breakpoint to if (adatB[i,j].InvokeRequired) before stepping, then make sure that the same parameters are being received to verify that the Invoke is triggering SetText as expected. (Step Into would be simpler, but I'm not sure that would work on an Invoke Line.)
If all that is working, then check if the display updates then adatB[i, j].Text = adat2; executes in the debugger.
I think your code is updating the display like you want it to, but it's not working properly in other regards. In one of my tests, it is just setting the first cell to "2" over and over again, so you won't see any change. You need to verify that the code is doing the right work before you verify that the display is updating properly. I think you may see many problems from having 3 threads running simultaneously which can all update or read the same global values when other threads are assuming these values (like jj) are not changing between lines. I would suggest not sharing data between threads if you are not very experienced with multi-threaded programming. Perhaps you can re-implement this as a single-threaded program that calls an update function periodically instead.
I'm currently working on a chatting program and the idea is to make it a secret one (Kind of like Facebook has the secret chat function).
My messages are sent to a listBox component and I want that every 10 or 'n' seconds the oldest message would get deleted. I
was trying to mark every message with an index but didn't quite understand how that works.
What I'm asking if maybe you guys know a function or could help me write one that does just that. I'm using Visual Studio 2015 Windows Forms, C#.
Well, when you have a ListBox, the items are all indexed since it's an object collection (an array of objects). Starting from 0 and going upwards for newer entries.
So let's say we add 3 items to our ListBox
listBox1.Items.Add("Item 1"); //Index 0
listBox1.Items.Add("Item 2"); //Index 1
listBox1.Items.Add("Item 3"); //Index 2
All you would have to do, is create a thread that runs in the background that deletes the item at index 0 (the oldest entry) each time.
new Thread(() =>
{
while(true)
{
if(listBox1.Items.Count > 0) //Can't remove any items if we don't have any.
{
Invoke(new MethodInvoker(() => listBox1.Items.RemoveAt(0))); //Remove item at index 0.
//Needs invoking since we're accessing 'listBox1' from a separate thread.
}
Thread.Sleep(10000); //Wait 10 seconds.
}
}).Start(); //Spawn our thread that runs in the background.
In C# WinForms a ListBox contains ListBoxItems which are a ObjectCollection (msdn-link)
So you can add any Object you like, the message which will be displayed comes from the DisplayMember
So for example
public class MyMessage {
public DateTime Received { get; set; }
public string Message { get; set; }
public string DisplayString
{
get { return this.ToString(); }
}
public string ToString() {
return "[" + Received.ToShortTimeString() + "] " + Message;
}
}
can be added as ListBoxItem.
Setting the DisplayMember to "DisplayString" (more here) will get you the correct output.
now you can iterate through the ListBoxItems, cast them as MyMessage and check the time when they were received.
I don't know if you thought about this but here's a way you could achieve this task.
First create an List of strings
List<string> list1 = new List<string>();
To use the List feature you will have to include collections in the form
using System.Collections;
Now comes the tricky part.
First declare a static integer variable globally i.e. outside all classes.
static int a;
Whenever you receive a message(considering your messages will be in string format) you've to add that string to list1 which you created.
list1.Add("the received message");
Now you've to declare a Timer (If you're new, check out how timers work). Windows forms already has timers, using that will be preferable.
The timer sends a Tick event after the desired time.
private void timer1_Tick(object sender, EventArgs e)
{
a = list1.Count() - 1; //Count will return the number of items in the list, you subtract 1 because the indexes start from 0
list1.RemoveAt(a);
listBox.Items.Clear();
foreach(string x in list1)
{
listBox.Items.Add(x);
}
}
What this code will do is, at every Tick event of the timer it will refresh the listbox, remove the last element from the array, and refill the listbox with the rest.
To use the timer just drag and drop it on the form. It's all GUI based and easy to figure out.
Let me know if you've doubts.
Tip: Make maximum use of try{} & catch{} blocks to avoid app crashes.
Objective
I'm trying to build a progress tracking mechanism which supports "branching".
Abstract
The principal concept here is that at every stage I know the current index and count of steps till this stage is complete.
Sample Scenario
var tasks = new Task[]
{
new Task(5), // 5 sub tasks
new Task(2), // 2 sub tasks
};
Assuming these items are run serially, progress percentage would look as follows:
0%
10%
20%
30%
40%
50%
50%
75%
100%
100%
Question Time!
First of all, what are the correct terms for what I'm doing? I have been unable to properly search because of this.
Secondly, what are the mathematics of what I'm doing? What are the variables that I have to track?
Final Product
I would like to end up with an interface that looks like this:
class TaskManagerExample
{
void Execute(Task[] tasks)
{
var pm = new ProgressManager(); // <- this class does the magic
// v-- and this is how the magic is used :)
pm.ProgressChanged += (object sender, EventArgs e) =>
{
progressBar1.Value = (sender as ProgressManager).TotalProgress;
};
pm.SetTotal(tasks.Length);
foreach (var task in tasks)
{
task.Execute(pm.Branch());
pm.NextStep();
}
}
}
class Task
{
protected int SubTasks = 0;
public Task(int subTasks){ this.SubTasks = subTasks; }
public void Execute(ProgressManager pmb)
{
pmb.SetTotal(this.SubTasks);
for(int i = 0; i < this.SubTasks; i++)
{
// do something
pmb.NextStep();
}
}
}
My problem is the implementation for ProgressManager. I've been able to achieve a parent-child relation so Branch() and NextStep() are ok. I'm mostly confused about how TotalProgress should be implemented.
How would one go through the tree to calculate the right progress position?
I am taking over a C# code from someone who implemented a desktop application to read real time data from the Serial Port and displaying it in charts (using the Chart Class).
The code seems to be working, but is very slow. It seems to be updating the chart around once in 4 seconds (0.25Hz). However, I can see that it is multi-threaded and has no delay commands, so I don't understand why it is running so slow. Could the updating of charts slow it down? Ideally I would like to achieve 1000 data points per second (1kHz), displaying it in real time and saving it to the hard disk, where the size of each data point is about 30 bytes.
I spent few days understanding the code, but it's too cumbersome to follow, all written in a single file, with no comments. Is my goal of reading 1000 data points per second realistic/achievable?
I'm also considering to re-write the code (as opposed to trying to fix it), considering it's only about 2,500 lines long. Any tips would be appreciated. Also, if I rewrite the code, what language might be better for this application?
I developed some code where I got significant performance improvement, it may work for you. Here is what I did-
Step 1: I would first identify, which one is the bottle neck, drawing/rendering of the chart
or serial port
Step 2: If you find its the rendering-- then add this in your form/chart setup, it will draw much faster. But first double check to make sure you're not in remote desktop mode.
<!-- language: c# -->
// No double buffering for remote, only local
public bool OptimizeOfLocalFormsOnly(System.Windows.Forms.Control chartControlForm)
{
if (!System.Windows.Forms.SystemInformation.TerminalServerSession)
{
SetUpDoubleBuffer(chartControlForm);
return true;
}
return false;
}
public static void SetUpDoubleBuffer(System.Windows.Forms.Control chartControlForm)
{
System.Reflection.PropertyInfo formProp =
typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
formProp.SetValue(chartControlForm, true, null);
}
I assume you using winform application :
Use serialPort component :
Configure its properties : (BaudRate, DataBits, StopBits, Parity ...)
Make use of its event (DataReceived) to collect your inputs.
You can send commands in a loop and collect the inputs/drawing them on chart component roughly like :
while(/*some condition*/)
{
serialPort.Write(/* your command */);
// you have to think of response time
// so implement something that waits a bit before calling the port again
// I would do it using timers
int tick= Environment.TickCount;
while(Environment.TickCount - tick <= 100) // wait 100 milliseconds
{
Application.DoEvents();
}
}
// collect the data as:
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// use according to your needs, for example
string data = "";
int readByte;
int available;
available = serialPort.BytesToRead;
if(available >= 30) // 30 bytes as stated in your question
{
for(int i=0; i<30; i++)
{
readByte = serialPort.ReadByte();
data += String.Format("{0:2X}", readByte);
}
// you can call some methods to save/display your collected data from here
save_to_file(data);
display_to_chart(data);
}
}
I developed a similar app where I was displaying 16charts * 256 samples/sec. Storing the data in a buffer and creating a separate thread for updating the charts worked for me.
When new data is read, data is stored in a list or array. Since it is real-time data, the timestamps are also generated here. Using the sample rate of the data acquired: timeStamp = timeStamp + sampleIdx/sampleRate;
public void OnDataRead(object source, EEGEventArgs e)
{
if ((e.rawData.Length > 0) && (!_shouldStop))
{
lock (_bufferRawData)
{
for (int sampleIdx = 0; sampleIdx < e.rawData.Length; sampleIdx++)
{
// Append data
_bufferRawData.Add(e.rawData[sampleIdx]);
// Calculate corresponding timestamp
secondsToAdd = (float) sampleIdx/e.sampleRate;
// Append corresponding timestamp
_bufferXValues.Add( e.timeStamp.AddSeconds(secondsToAdd));
}
}
Then, create a thread that sleeps every N ms (100ms is suitable for me for a 2 seconds display of data, but if I wanna display 10 seconds, I need to increase to 500ms of sleep time for the thread)
//Create thread
//define a thread to add values into chart
ThreadStart addDataThreadObj = new ThreadStart(AddDataThreadLoop);
_addDataRunner = new Thread(addDataThreadObj);
addDataDel += new AddDataDelegate(AddData);
//Start thread
_addDataRunner.Start();
And finally, update the charts and make the thread sleep every N ms
private void AddDataThreadLoop()
{
while (!_shouldStop)
{
chChannels[1].Invoke(addDataDel);
// Sleeep thread for 100ms
Thread.Sleep(100);
}
}
The AddData method, simply reads the X (timestamp) and Y values stored in the buffer and add its to the charts using ptSeries.Points.AddXY(xValue, yValue)
I'm Doing a project on FileTransfer in which i have a listview , i will get events from one of my class file for updating the percentage of the file sent so far,after receiving it i will place the percentage in my listview ,while doing that the listview got
a flickering effect how to avoid it.i used application.doevents() but it doesnt works. i have seen in torrents while updating the percent the list doesnt get flickered
how to achieve this .
void Sender_Progress(int CurrentValue, string Ip) // here im receiving Events
{
try
{
//if (CurrentValue == 1)
// UpdateTimer.Enabled = true;
//list_send.Items[CurrentValue].SubItems[4].Text = Ip.ToString();
//Application.DoEvents();
obj = new object[] {CurrentValue, Ip };
list_send.Invoke(new UpdateList(UpList), obj);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void UpList(int Val, string ind) // here im updating the listview
{
Application.DoEvents();
int index = 0;
index = Convert.ToInt32(ind);
index = index - 1;
list_send.Items[index].SubItems[4].Text = Val.ToString();
if (Val == 100)
{
list_send.Items[index].SubItems[2].Text = "Completed.";
//UpdateTimer.Enabled = false;
}
//Application.DoEvents();
}
Firstly, you don't need the DoEvents, since you are already correctly working on two threads. Remove that. After that, I expect the problem is simply doing too much too quickly. Is it possible to batch updates, and only send an update, say, every 20? 50? times? It isn't clear what the control is, but many have multiple-update modes; for example with ListView:
theList.BeginUpdate();
try {
// make multiple updates here...
} finally {
theList.EndUpdate();
}
I would then see about passing over a list of updates, say, every 20 times (unless each takes a considerable time) [note it must be a different list per Invoke, and you need to remember to send any remaining items at the end, too].
Use worker thread - it's available from the toolbox and has two events that are invoked in the main (UI) thread.
The Progress event can be used to signal the listbox that it need to refresh or that the task was completed.
i overcome the flickering effect succesfully,im getting events frequently ,i will get an integer everytime, i will store it in a variable and compare it with next variable received by the event if it matches i wont invoke the listview,otherwise i will invoke it.now the flickering goes away. thanks all.