Asynchronous Call to Timer - c#

I am trying to create an application that shows the system statistics but it also executes a timer each second to update the current CPU clock speed. I have tried numerous solutions but none seem to work for me. I will attach my code below. I am using the System.Management DLL to call the stats I am wanting. Thank you!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Management;
namespace ezCPU
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.Text = this.Text + " - v" + Application.ProductVersion;
getCPUInfo();
}
public string convertClockSpeed(string s)
{
double clockSpeed = Convert.ToDouble(s);
double newClockSpeed = (clockSpeed / 1000);
return Math.Round(newClockSpeed, 2).ToString() + " GHz";
}
public void getCPUInfo()
{
ManagementObjectSearcher myProcessorObject = new ManagementObjectSearcher("select * from Win32_Processor");
foreach (ManagementObject obj in myProcessorObject.Get())
{
string cpuName = obj["Name"].ToString();
txtCPUName.Text = cpuName;
string cpuManufacturer = obj["Manufacturer"].ToString();
if (cpuManufacturer == "GenuineIntel")
{
txtCPUManufacturer.Text = "Genuine Intel";
}
else
{
txtCPUManufacturer.Text = cpuManufacturer;
}
string cpuCores = obj["NumberOfCores"].ToString();
txtCores.Text = cpuCores;
string cpuThreads = obj["ThreadCount"].ToString();
txtThreads.Text = cpuThreads;
string cpuMaxSpeed = obj["MaxClockSpeed"].ToString();
txtClockSpeed.Text = convertClockSpeed(cpuMaxSpeed);
}
}
private void cpuTimer_Tick(object sender, EventArgs e)
{
ManagementObjectSearcher myProcessorObject = new ManagementObjectSearcher("select * from Win32_Processor");
foreach(ManagementObject obj in myProcessorObject.Get())
{
string currentClockSpeed = obj["CurrentClockSpeed"].ToString();
txtCPUSpeed.Text = convertClockSpeed(currentClockSpeed);
}
}
}
}
This is the result of the code. However, I am unable to move the form around while it is still updating.

Have you tried the windows forms timer? It has the elapsed event that even spins up a background thread to do the work, keeping your ui responsive:
https://learn.microsoft.com/en-us/dotnet/api/system.timers.timer.elapsed?redirectedfrom=MSDN&view=netframework-4.8
public class Form1: Form
{
public System.Windows.Forms.Timer aTimer = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
// Create a timer and set a two second interval.
aTimer.Interval = 2000;
// Hook up the tick event for the timer.
aTimer.Tick += OnTimedEvent;
// Have the timer fire repeated events (true is the default)
aTimer.AutoReset = true;
// Start the timer
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program at any time... ");
Console.ReadLine();
}
private void OnTimedEvent(object sender, EventArgs e)
{
// update your statistics here
}
}
If you want to update the ui there, then the tick event is the way to go: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.timer.tick?view=netframework-4.8

Related

how do I make windows service complete all code before repeating process

So I created a service to run on a server and look at different folder shares and put them in a database table for a customized search but it pulls a datatable of search locations in and iterates through them one at a time which worked great with small test folders. Now that I tried to use it for real it does not make it through the first folder path before my timer restarts it. I could make it time longer but I basically want this to run constantly and start over as soon as the first one is done or not sure if I can run all paths at the same time. I had it running every 30 Minutes but definitely not long enough.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace MFTSearchService
{
public partial class MFTSearchService : ServiceBase
{
Timer timer = new Timer(); // name space(using System.Timers;)
public MFTSearchService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
WriteToFile("Service is started at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = TimeSpan.FromMinutes(10).TotalMilliseconds; //number in milisecinds
timer.Enabled = true;
//global::MFTSearchService.Search.SearchStart();
}
protected override void OnStop()
{
WriteToFile("Service is stopped at " + DateTime.Now);
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
WriteToFile("Service is recall at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = TimeSpan.FromMinutes(30).TotalMilliseconds; //number in milisecinds
timer.Enabled = true;
global::MFTSearchService.Search.SearchStart();
}
public void WriteToFile(string Message)
{
string path = AppDomain.CurrentDomain.BaseDirectory + "\\Logs";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\Logs\\ServiceLog_" + DateTime.Now.Date.ToShortDateString().Replace('/', '_') + ".txt";
if (!File.Exists(filepath))
{
// Create a file to write to.
using (StreamWriter sw = File.CreateText(filepath))
{
sw.WriteLine(Message);
}
}
else
{
using (StreamWriter sw = File.AppendText(filepath))
{
sw.WriteLine(Message);
}
}
}
}
}
Instead of calling
global::MFTSearchService.Search.SearchStart();
in your timer, you can add a BackgroundWorker and start it in your timer. For every tick on your timer, you can check if Backgroundworker is busy or not. BackgroundWorker will not run until it's done if you check it before running it.
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
WriteToFile("Service is recall at " + DateTime.Now);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = TimeSpan.FromMinutes(30).TotalMilliseconds; //number in milisecinds
timer.Enabled = true;
if (!backgroundWorker1.IsBusy())
{
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
global::MFTSearchService.Search.SearchStart();
}
Background worker will not lock your main thread so your timer will continue looping. So you're free to put any interval to it.

Background worker still freezing ui

Even tho I setup a background worker, I can't seem to make it not freeze the UI.
I looked around online but could not find a fix. I have tried creating basic threads and that worked but I need to also update UI stuff as it runs so thats why I switched to backgroundworkers, but if you could help me figure out how to use a basic thread and get that working that would be ok.
using MediaToolkit;
using MediaToolkit.Model;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using VideoLibrary;
namespace ConsoleApp1
{
public partial class Form1 : Form
{
private List<VideoInfo> vids = new List<VideoInfo>();
private List<VideoInfo> failedVids = new List<VideoInfo>();
private int threads = 0;
BackgroundWorker worker;
private delegate void DELEGATE();
static void Main(string[] args)
{
Form1 form = new Form1();
form.ShowDialog();
}
public Form1()
{
InitializeComponent();
worker = new BackgroundWorker();
}
private void button1_Click(object sender, EventArgs e)
{
if(threads == 0)
{
progressBar1.Maximum = vids.Count;
progressBar1.Value = 0;
failedVids.Clear();
worker.DoWork += doWork;
worker.RunWorkerAsync();
//downloadVid();
}else
{
Console.WriteLine("Waiting for threads" + threads);
}
/*Thread thread1 = new Thread(new ThreadStart(downloadVid));
thread1.Start();*/
}
private void button1_Click_1(object sender, EventArgs e)
{
VideoInfo vid = new VideoInfo(tbLink.Text, tbTitle.Text, tbArtist.Text);
vids.Add(vid);
tbLink.Clear();
tbTitle.Clear();
listView1.Items.Add(vid.getLink());
}
private int downloadThread(int i)
{
Console.WriteLine(i);
var source = #"C:\Users\derri\Downloads\DownloadTest\";
var youtube = YouTube.Default;
VideoInfo vidInfo = vids[(int) i];
var vid = youtube.GetVideo(vidInfo.getLink());
Console.WriteLine(vidInfo.getLink());
try
{
File.WriteAllBytes(source + vid.FullName, vid.GetBytes());
}
catch (Exception e)
{
failedVids.Add(vids[(int)i]);
Console.WriteLine(e);
goto End;
}
var inputFile = new MediaFile { Filename = source + vid.FullName };
var outputFile = new MediaFile { Filename = $"{source + vidInfo.getArtist() + " - " + vidInfo.getTitle()}.mp3" };
using (var engine = new Engine())
{
engine.GetMetadata(inputFile);
engine.Convert(inputFile, outputFile);
}
File.Exists(outputFile.Filename);
File.Delete(inputFile.Filename);
setTags(vidInfo.getArtist(), vidInfo.getTitle());
End:
threads--;
return 1;
}
private void doWork(object sender, DoWorkEventArgs e)
{
Delegate del = new DELEGATE(downloadVid);
this.Invoke(del);
}
private void downloadVid()
{
int prog = 0;
for (int i = 0; i < vids.Count; i++)
{
Console.WriteLine(i);
while ((threads > 5)) { }
Thread thread = new Thread(() => { prog += downloadThread(i); });
thread.Start();
threads++;
System.Threading.Thread.Sleep(1000);
//thread.Join();
/*ParameterizedThreadStart start = new ParameterizedThreadStart(downloadThread);
Thread t = new Thread(start);
t.Start(i);
progressBar1.Value++;
threads++;*/
}
while (threads > 0){}
foreach (VideoInfo failedVid in failedVids)
{
listView2.Items.Add(failedVid.getLink());
}
listView1.Clear();
vids.Clear();
}
private void setTags(string artist, string title)
{
TagLib.File file = TagLib.File.Create("C:\\Users\\derri\\Downloads\\DownloadTest\\" + artist + " - " + title + ".mp3");
file.Tag.Artists = (new String[] { artist });
file.Tag.Title = (title);
file.Save();
}
}
}
this.Invoke will run on the UI thread.
Look into how to use either ReportProgress or RunWorkerCompleted events of the BackgroundWorker class. The both allow you to pass data from the background thread to the UI thread.

Delegate loads the Alert Form but I can't use any of the components.. its stuck

The problem is below. Here's my code...
// Contents of Form1.cs
// Usual includes
namespace ProcessMonitor
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Boolean getStatus()
{
// Returns true if the system is active
if (label1.Text.Equals("Active"))
return true;
return false;
}
private void button1_Click(object sender, EventArgs e)
{
if(getStatus())
{
label1.Text = "Not Active";
button1.Text = "Activate";
}
else
{
label1.Text = "Active";
button1.Text = "Deactivate";
}
}
private void Form1_Load(object sender, EventArgs e)
{
Monitor mon = new Monitor(this);
mon.Run();
}
}
}
// Contents of Monitor.cs
// Usual includes
using System.Management;
using System.Diagnostics;
using System.Threading;
namespace ProcessMonitor
{
class Monitor
{
Form1 parent;
private void ShowAlert(Alert al)
{
al.Show();
}
public Monitor(Form1 parent)
{
this.parent = parent;
}
public void InvokeMethod()
{
//This function will be on main thread if called by Control.Invoke/Control.BeginInvoke
Alert frm = new Alert(this.parent);
frm.Show();
}
// This method that will be called when the thread is started
public void Run()
{
var query = new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 0, 0, 0, 1),
"TargetInstance isa \"Win32_Process\");
while (true)
{
using (var watcher = new ManagementEventWatcher(query))
{
ManagementBaseObject mo = watcher.WaitForNextEvent();a
//MessageBox.Show("Created process: " + ((ManagementBaseObject)mo["TargetInstance"])["Name"] + ",Path: " + ((ManagementBaseObject)mo["TargetInstance"])["ExecutablePath"]);
ManagementBaseObject o = (ManagementBaseObject)mo["TargetInstance"];
String str = "";
foreach (PropertyData s in o.Properties)
{
str += s.Name + ":" + s.Value + "\n";
}
this.parent.Invoke(new MethodInvoker(InvokeMethod), null);
}
}
}
}
}
Alert.cs is just a blank form with a label that says “new process has started”. I intend to display the name of the process and location, pid, etc. by passing it to this alert form via the Thread (i.e. class Monitor). I have deliberately made the thread load in form_load so that I can resolve this error first. Adding it as a thread properly after the main form loads fully is a later task. I need to fix this first..
The delegate creates the Alert form but I can’t click on it, its just stuck. Need help to solve this.
Your while loop in Run is blocking the UI thread.
by passing it to this alert form via the Thread
You never actually create a new thread or task here - you just run code which executes in the UI thread, and causes an infinite loop. This will prevent the main form, as well as your Alert form, from ever displaying messages.
You need to push this into a background thread in order for it to work, ie:
private void Form1_Load(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(_ =>
{
Monitor mon = new Monitor(this);
mon.Run();
});
}

Windows Form - Running python script, redirected output delayed

I'm running a windows form with a background worker to update a textbox based on the output of a python script. Its all working pretty well, except the redirected output is not in real time; its delayed pretty significantly.
Any ideas how I can increase the redirected outputs response time?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.IO;
namespace JiraHeartBeat
{
public partial class Form1 : Form
{
delegate void AppendTextDelegate(string text);
BackgroundWorker Worker = new BackgroundWorker();
public Form1()
{
InitializeComponent();
Worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
}
void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
StartButton.PerformClick();
}
private void StartButton_Click(object sender, EventArgs e)
{
if (!Worker.IsBusy)
{
Worker.RunWorkerAsync();
}
}
public void Worker_DoWork(object sender, DoWorkEventArgs e)
{
Process pro = new Process();
pro.StartInfo.RedirectStandardOutput = true;
pro.StartInfo.RedirectStandardError = true;
pro.StartInfo.UseShellExecute = false;
pro.StartInfo.CreateNoWindow = true;
pro.EnableRaisingEvents = true;
pro.OutputDataReceived += new DataReceivedEventHandler(OnDataReceived);
pro.ErrorDataReceived += new DataReceivedEventHandler(OnDataReceived);
pro.StartInfo.FileName = "C:\\Python27\\python.exe";
pro.StartInfo.Arguments = "\"C:\\Python27\\myscript.py\"";
try
{
pro.Start();
pro.BeginOutputReadLine();
pro.BeginErrorReadLine();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
Thread.Sleep(5000 * 60);
}
public void OnDataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
string temp = (e.Data) + Environment.NewLine;
appendText(temp);
}
}
public void appendText(string text)
{
if (ResultTextBox.InvokeRequired)
{
ResultTextBox.Invoke(new AppendTextDelegate(appendText), new object[] { text });
}
else
{
ResultTextBox.AppendText(text);
}
}
}
}
Actually, the issue is that Python does not redirect output until the script is complete. I believe IronPython will redirect while the script is running (have not tested this though), but unfortunately, regular Python must wait for the script to end before redirecting output.
Try removing the below line from the Worker_DoWork, I suspect it is delaying the execution of the RunWorkerCompleted event.
Thread.Sleep(5000 * 60);
EDIT
Since the above approach was attempted and did not solve the problem entirely I investigated a bit further and confirmed that when capturing the output from a python script the response is delayed. However, by adding a call to sys.stdout.flush() I was able to get the desired behavior. Here is the python script I used which worked successfully in my test.
import time
import sys
for x in xrange(0,11):
print x
time.sleep(1)
sys.stdout.flush()

Task.Factory.StartNew() not firing the ElapsedEventHandler event

In my following code, the Timer_Elapsed event is not hitting.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using System.Reflection;
using System.Diagnostics;
namespace Logger
{
internal class Country
{
public string CountryName { get; set; }
public string CountryCode { get; set; }
}
internal class CountryLogger
{
List<Country> countries = new List<Country>()
{
new Country{CountryName = "India", CountryCode="IND"},
new Country{CountryName = "United States of America", CountryCode="USA"},
new Country{CountryName = "United Kingdom", CountryCode="UK"},
new Country{CountryName = "Australia", CountryCode="AUS"}
};
public void WriteToLog()
{
string fileName = #"C:\ParallelLog.txt";
using (StreamWriter writer = new StreamWriter(fileName, true))
{
foreach (Country Country in countries.AsParallel().AsOrdered())
{
writer.WriteLine("{0} - {1}", Country.CountryName, Country.Count ryCode);
writer.WriteLine();
}
}
}
}
internal class Program
{
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Enabled = true;
timer.Interval = 3 * 60 * 1000;
timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
}
static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//for (int i = 0; i < 10; i++)
//{
Task task = Task.Factory.StartNew(() =>
{
CountryLogger countriesLogger = new CountryLogger();
countriesLogger.WriteToLog();
});
//}
}
}
}
Also the Task task = Task.Factory.StartNew(() => object is not looping through the for loop (Commented because it doesn't work).
Can someone suggest the better way of writing this code to work?!
What should the first program thread do whilst letting the timer run?
Here, I'm just waiting for the user to hit return:
static void Main(string[] args)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
timer.Interval = 3 * 60 * 1000;
timer.Enabled = true;
Console.WriteLine("Press return to exit");
Console.ReadLine();
GC.KeepAlive(timer); //Can't decide if this is needed or not
}
What is important is that if you return from Main (or just hit that final }), your program is going to exit. I can't remember whether timers keep themselves alive in terms of Garbage Collection, so I've added a GC.KeepAlive just in case.
I've also switched around the order of assignments on the timer - so that it's not enabled until I know that the handler is attached and that the interval is set correctly.

Categories

Resources