Click here to Skip to main content
15,846,038 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

I am working on one C# application. This application does connection with device.
In that application one monitor functionality is present . User can select few parameters from connected device and pest in to monitor window (C# from) and starts monitoring (update monitor form for new values) and logging (write these parameters in one .csv file).
I have used one form.timer on monitor form and doing this functionality
C#
private void Sampling_Timer_Tick(object sender, EventArgs e)
        {
for (int iCount = 0; iCount < SamplingParameterList.Length; iCount++) //SamplingParameterList.Length mostly have 100+ value
               {
//read parameter value and display it in monitor list.
}
//write values in .csv file
        }


But when I start its timer, my application becomes slow. I think UI thread gets blocked. (if I click on any check box then for getting checked mark on that check box application takes 30 sec)

I need this timer to work on accurate interval. Means if I set interval at 1 second then each line in log file should get captured at one second only and user should be able to work on other forms also.

please help me on this.
Posted

1 solution

You can start a new thread inside your tick event.
That way you will spend very little time blocking the GUI.

You can start reading about threads here: Threading (C# and Visual Basic)[^]

And here is a short example:
C#
using System.Threading;

private void Sampling_Timer_Tick(object sender, EventArgs e)
{
    Thread worker = new Thread(new ThreadStart(DoSomething));
    worker.Name = "Doer";
    worker.IsBackground = true;
    worker.Start();
}

private void DoSomething()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    
    // Do your stuff here, but keep the process time below your tick time
    // (1 second)
    
    // Also if you want to update, beware of cross thread isssues
    // Loo into how to use .BeginInvoke

    sw.Stop();
    string elapsedTime = sw.ElapsedMilliseconds.ToString();
    // Present the elapsed time in the GUI
}

[UPDATE]
I added a Stopwatch that can be used to measure the time you spend in the worker method.
If you spend more than one second reading values from the device you have a little problem, as the next timer event will trigger before you have finished reading from your device.
You basically have two ways to solve this dilemma:
1. Read fewer parameters, if that is possible.
2. Make the time between events long enough for all the parameters to be read.


The solution with adding a lock will not work well in the long run as you will soon pile up a queue with requests to read from the device and this queue will just be longer and longer until you run out of resources.


There are several other methods to achieve the same result, but this is pretty simple to start with.
For example, the BackgroundWorker class can be used as well.
 
Share this answer
 
v3
Comments
Member 11379036 15-Sep-15 8:31am    
in back ground worker thread my parameter reading process is working well. Some parameters are failed to read. Is there any other solution.
Philippe Mori 15-Sep-15 12:31pm    
You have to be more specific if you need specific help otherwise we could only give general advices.
Member 11379036 16-Sep-15 1:56am    
In my application parameter gets read from connected device in monitor functionality.
If I use thread and there are more than 20 parameters reading in monitor then parameter reading process gets failed.
Device can read only one parameter at a time, may be in thread implementation at a time 2 parameter sends a request to read from connected device and one of parameter gets failed. If parameter gets failed in timer I terminate thread, so monitor gets failed. (Monitor should run until user stops it)
But when I use only timer then parameter reading mechanism is not affected but it blocks UI thread.
Member 11379036 16-Sep-15 2:21am    
I tried with lock. In that implementation also I got error as parameter read fail.
I use lock as following

private void MoniotrSamplingAndLoggingProcess()
{
String strFileLine = String.Empty;
Global.com_port_busy_flg = true;
Global.SleepTimeForReadcommand = 80;
Global.m_ComPort.MAX_RETRY_COUNT = 5;
try
{
for (int iCount = 0; iCount < SamplingParameterList.Length; iCount++)
{
lock (_locker)
{
if (SamplingParameterList[iCount].Size.Contains("Array"))
SamplingParameterList[iCount].value = Global.ObjCmd.send_read_packet_command("01", SamplingParameterList[iCount].Address, SamplingParameterList[iCount].Size, SamplingParameterList[iCount].Scalar, SamplingParameterList[iCount].Type, SamplingParameterList[iCount].Range, SamplingParameterList[iCount].FeatureName);

else
SamplingParameterList[iCount].value = Global.ObjCmd.send_read_parameter_command("01", SamplingParameterList[iCount].Address, SamplingParameterList[iCount].Size, SamplingParameterList[iCount].Scalar, SamplingParameterList[iCount].Type, SamplingParameterList[iCount].Range, SamplingParameterList[iCount].Resolution);
}
if (SamplingParameterList[iCount].value.Equals("-1"))
{
Sampling_Timer.Stop();
MessageBox.Show("Device disconnected");
break;
}
else
{
// DG_Monitor.Rows[iCount].Cells[1].Value = SamplingParameterList[iCount].value;
}

//if logging is on then set values in string
if (Chk_LogFile.Checked.Equals(true))
{
strFileLine += SamplingParameterList[iCount].value + ",";
}
}
}
catch (Exception ex)
{

MessageBox.Show(ex.Message, Global.ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Global.com_port_busy_flg = false;

if (Global.ping_timer_exec_missed_flg.Equals(true))
{
Global.objParameterScreen.PingSession();
Global.ping_timer_exec_missed_flg = false;
}

//if logging is on then write parameter values in log file
if (Chk_LogFile.Checked.Equals(true))
{
TextWriter tw = new StreamWriter(TB_LogFileName.Text, true);
DateTime dt = DateTime.Now;
try
{
if (Is_LogFile_Header_Written.Equals(false))
{
if (!File.Exists(TB_LogFileName.Text))
{
Directory.CreateDirectory(Path.GetDirectoryName(TB_LogFileName.Text));
File.Create(TB_LogFileName.Text).Close();
}
String strFileHeaderLine = "Time,";
for (int iCountLogHeader = 0; iCountLogHeader < SamplingParameterList.Length; iCountLogHeader++)
strFileHeaderLine += SamplingParameterList[iCountLogHeader].Name + ",";
tw.WriteLine(strFileHeaderLine);
Is_LogFile_Header_Written = true;
}
strFileLine = dt.ToString("MM/dd/yyyy HH:mm:ss.fff", CultureInfo.InvariantCulture) + "," + strFileLine;
tw.WriteLine(strFileLine);
tw.Close();
}
catch (Exception ex)
{
Sampling_Timer.Stop();
Sampling_Timer.Enabled = false; //c
Member 11379036 16-Sep-15 2:24am    
declare lock as
static readonly object _locker = new object();

I used this MoniotrSamplingAndLoggingProcess () in timer tick event
private void Sampling_Timer_Tick(object sender, EventArgs e)
{
Thread worker = new Thread(new ThreadStart(MoniotrSamplingAndLoggingProcess));
worker.Name = "Doer";
worker.IsBackground = true;
worker.Start(); }

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900