I am trying to develop a simple application that must have GUI components. It will be a service in the taskbar tray but must query the database every few minutes to check for changes, then post to a web server the results. It will run 24/7.
This is my first application, and so have been getting some help along the way from SO. When I first used the FluentScheduler, I had trouble (C# FluentScheduler Job not Repeating) but got it working as a simple proof of concept with a console app.
As I tried taking what I had learned and implementing it with my Windows Forms solution, I couldn't get it working at all because once it ran the Application.Run(ThisForm); command, the scheduler did nothing. Eventually while troubleshooting, I stumbled across this:
https://github.com/fluentscheduler/FluentScheduler/issues/169
I see that you're using the library from something like a Windows Forms/WPF application. Starting threads/tasks from a GUI application is a pain in the ***, maybe that's what's biting you. Fingers crossed to be something else, diving up on STA threads, dispatchers, synchronization contexts and alikes is no fun.
So now I am left wondering what I am supposed to do? Am I supposed to develop the scheduled tasks as a console app leaving an API for a WPF application to communicate with, or am I supposed to work through the pain he is describing and make it work within WPF?
As this is my first C# project, it seems pretty complicated to separate the two components, but am willing to learn if that is the right choice. I am still very early in the project just doing proof of concepts of each needed feature and so can easily switch to WPF, UWP, or whatever else is most appropriate. It will have minimal GUI, just a few forms to fill out username / password type stuff and options to sync.
Even though this FluentScheduler has about a quarter million downloads, maybe there is a better one that doesn't suffer from the same limitations you could recommend.
Based on the earlier post you linked to, I see a few problems with your code:
Your call to JobManager.Initialize is unreachable because it occurs after Application.Run, which blocks until the application shuts down (e.g., when the last window is closed).
The FluentScheduler will schedule your job to run on an arbitrary worker thread, but your action accesses or manipulates UI elements. In both WPF and Windows Forms, you can only touch UI elements from the main thread. If your job needs to touch the UI, it must first marshal itself back onto the UI thread.
The scheduled action in your original post does not make sense:
Action someMethod = new Action(() =>
{
Form1 ThisForm = new Form1();
ThisForm.Text ="HELLO";
});
Specifically, you are creating a new window that is never shown, rather than modifying one that already exists.
Here is a simple example project that you should be able to use as a starting point. It displays the current time, updating once per second. I used WPF, as I haven't used Windows Forms in years, and there's no compelling reason to use it these days.
SchedulerText.xaml:
<Window x:Class="WpfTest.SchedulerTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<TextBlock x:Name="_textBlock"
FontSize="18pt"
TextAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</Window>
SchedulerTest.xaml.cs:
using System;
using FluentScheduler;
namespace WpfTest
{
public partial class SchedulerTest
{
public SchedulerTest()
{
InitializeComponent();
JobManager.AddJob(
this.DoScheduledWork,
schedule => schedule.ToRunNow().AndEvery(1).Seconds());
}
private void DoScheduledWork()
{
// Go query your database, or do whatever your main job is.
// You don't want to do this on the UI thread, because it
// will block the thread and prevent user interaction.
DoPrimaryWorkOffUIThread();
// If you need to communicate some sort of result to the user,
// do it on the UI thread.
Dispatcher.Invoke(new Action(ShowResultsOnUIThread));
}
private DateTime _currentResult;
private void DoPrimaryWorkOffUIThread()
{
_currentResult = DateTime.Now;
}
private void ShowResultsOnUIThread()
{
_textBlock.Text = $"{_currentResult:h:mm:ss}";
}
}
}
Note that you don't have to initialize the job in the windows's constructor, but that would be the easiest place to do it.
Related
using System.Windows.Forms;
public class App
{
[STAThread]
public static void Main()
{
string fname;
using (var d = new OpenFileDialog())
{
if (d.ShowDialog() != DialogResult.OK)
{
return;
}
fname = d.FileName;
}
//Application.ExitThread();
for (; ;)
;
}
}
The above code shows me a file dialog. Once I select a file and press open, the for loop is executed, but the (frozen) dialog remains.
Once I uncomment Application.ExitThread() the dialog disappears as expected.
Does that work as intended? Why doesn't using make the window disappear? Where can I find more info about this?
You have discovered the primary problem with single-threaded applications... long running operations freeze the user interface.
Your DoEvents() call essentially "pauses" your code and gives other operations, like the UI, a chance to run, then resumes. The problem is that your UI is now frozen again until you call DoEvents() again. Actually, DoEvents() is a very problematic approach (some call it evil). You really should not use it.
You have better options.
Putting your long running operation in another thread helps to ensure that the UI remains responsive and that your work is done as efficiently as possible. The processor is able to switch back and forth between the two threads to give the illusion of simultaneous execution without the difficulty of full-blown multi-processes.
One of the easier ways to accomplish this is to use a BackgroundWorker, though they have generally fallen out of favor (for reasons I'm not going to get into in this post: further reading). They are still part of .NET however and have a lower learning curve then other approaches, so I'd still suggest that new developers play around with them in hobby projects.
The best approach currently is .NET's Tasks library. If your long running operation is already in a thread (for example, it's a database query and you are just waiting for it to complete), and if the library supports it, then you could take advantage of Tasks using the async keyword and not have to think twice about it. Even if it's not already in a thread or in a supported library, you could still spin up a new Task and have it executed in a separate Thread via Task.Run(). .NET Tasks have the advantage of baked in language support and a lot more, like coordinating multiple Tasks and chaining Tasks together.
JDB already explained in his answer why (generally speaking) your code doesn't work as expected. Let me add a small bit to suggest a workaround (for your specific case and for when you just need to use a system dialog and then go on like it was a console application).
You're trying to use Application.DoEvents(), OK it seems to work and in your case you do not have re-entrant code. However are you sure that all relevant messages are correctly processed? How many times you should call Application.DoEvents()? Are you sure you correctly initialize everything (I'm talking about the ApplicationContext)? Second problem is more pragmatic, OpenFileDialog needs COM, COM (here) needs STAThread, STAThread needs a message pump. I can't tell you in which way it will fail but for sure it may fail.
First of all note that usually applications start main message loop using Application.Run(). You don't expect to see new MyWindow().ShowDialog(), right? Your example is not different, let Application.Run(Form) overload creates the ApplicationContext for you (and handle HandleDestroyed event when form closes which will finally call - surprise - Application.ExitThread()). Unfortunately OpenFileDialog does not inherit from Form then you have to host it inside a dummy form to use Application.Run().
You do not need to explicitly call dlg.Dispose() (let WinForms manage objects lifetime) if you add the dialog inside the form with the designer.
using System;
using System.Windows.Forms;
public class App
{
[STAThread]
public static void Main()
{
string fname = AskForFile();
if (fname == null)
return;
LongRunningProcess(fname);
}
private static string AskForFile()
{
string fileName = null;
var form = new Form() { Visible = false };
form.Load += (o, e) => {
using (var dlg = new OpenFileDialog())
{
if (dlg.ShowDialog() == DialogResult.OK)
fileName = dlg.FileName;
}
((Form)o).Close();
};
Application.Run(form);
return fileName;
}
}
No, you don't have to call Application.ExitThread().
Application.ExitThread() terminates the calling thread's message loop and forces the destruction of the frozen dialog. Although "that works", it's better to unfreeze the dialog if the cause of the freeze is known.
In this case pressing open seems to fire a close-event which doesn't have any chance to finish. Application.DoEvents() gives it that chance and makes the dialog disappear.
as I am new in multithreaded application I would like to have some advice from more experienced people before starting to write the code...
I need to queue data received on serial port in serial port event for further processing.
So I have the following event handler:
void jmPort_ReceivedEvent(object source, SerialEventArgs e)
{
SetStatusLabel("Iddle...", lbStatus);
SetPicVisibility(ledNotReceiving, true);
SetPicVisibility(ledReceiving, false);
String st = jmPort.ReadLine();
if (st != null)
{
lines.Enqueue(st); //"lines" is the ConcurrentQueue<string> object
StartDataProcessing(lines); //???
SetStatusLabel("Receiving data...", lbStatus);
SetPicVisibility(ledNotReceiving, false);
SetPicVisibility(ledReceiving, true);
}
else
{
jmPort.Close();
jmPort.Open();
}
}
Within the StartDataProcessing I need to dequeue strings and update MANY UI controlls (using the InvokeRequired...this I already know :-)).
What is the best approach and colision free (without deadlock) approach to achieve this?
How to call StartDataProcessing method in more threads and safely dequeue (TryDequeue) the lines queue, make all needed computations and update UI controlls?
I have to appoint that the communication is very fast and that I am not using the standard SerialPort class. If I simply write all received strings without further processing to console window it works just well.
I am working in .NET 4.5.
Thank you for any advice...
Updated question: Ok, so what will be the best way to run the task from the datareceived event using TPL? Is it necessary to create another class (object) that will process data and use callbacks to update UI or it is possible to load some form method from the event? I'll could be very happy if someone can give me the direction what exactly to do within the datareceived event. What to do as the first step because studying all possible ways is not the solution I have time for. I need to begin with some particular way... There is so many different possible multithreading approaches and after reading about them I am still more confused and I don't know what will be the best a fastest solution... Usual Thread(s), BackgroundWorker, TPL, async-await...? :-( Because my application uses .NET 4.5 I would like to use some state-of-the-art solution :-) Thank you for any advice...
So after a lot of trying it is working to my satisfaction now.
Finally I've used the standard .NET SerialPort class as the third-party Serial class causes somae problems with higher baudrates (115200). It uses WinAPI directly so the finall code was mixed - managed and unmanaged. Now, even the standard .NET 4.5 SerialPort class works well (I've let my application successfully running through a whole night).
So, for everyone that need to deal with C#, SerialPort and higher rates (only for clarification - the device sending messages to PC is the STM32F407 /using USART 2/. I've tried it also with Arduino Due and it works as well) my datareceived event is in the following form now:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
//the SetXXXXX functions are using the .InvokeRequired approach
//because the UI components are updated from another thread than
//the thread they were created in
SetStatusLabel("Iddle...", lbStatus);
SetPicVisibility(Form1.frm.ledNotReceiving, true);
SetPicVisibility(Form1.frm.ledReceiving, false);
String st = serialPort1.ReadLine();
if (st != null)
{
lines.Enqueue(st);
Task.Factory.StartNew(() => StartDataProcessing(lines)); // lines is global ConcurrentQueue object so in fact there is no need to pass it as parameter
SetStatusLabel("Receiving data...", lbStatus);
SetPicVisibility(Form1.frm.ledNotReceiving, false);
SetPicVisibility(Form1.frm.ledReceiving, true);
}
}
Within the StartDataProcessing function:
1. TryDequeue(lines, out str)
2. Use the ThreadPool.QueueUserWorkItem(lCallBack1, tmp); where tmp is needed part of the str (without EOF, without the message number etc.)
lCallBack1 = new WaitCallback(DisplayData);
Within the DisplayData function all the UI controls are updated
This approach mixes the ThreadPool and TPL ways but it is not a problem because the ThreadPool is used by TPL in background operation anyway.
Another working method I've tried was the following:
ThreadPool.QueueUserWorkItem(lCallBack, lines);
instead of :
Task.Factory.StartNew(() => StartDataProcessing(lines));
This method was working well but I've not tested it in over night run.
By my subjective perception the Task.... method updated the controls more smoothly but it can be only my personal feeling :-)
So, I hope this answer will help someone as I know from forums that many people are dealing with with unreliable communication based on the micocontroller <--> PC
My (surprising :-) ) conclusion is that the standard .NET SerialPort is able to handle messages even at higher baudrates. If you still run into troubles with buffer overrun then try to play with the SerialPort buffer size and SerialPort threshold. For me the settings 1024/500 are satisfactory (max size of the message send by microcontroller is 255 bytes so 500 bytes means that 2 messages are in buffer before the event is fired.)
You can also remove all SetXXXX calls from the datareceived event as they are not really needed and they can slow down the communication a little...
I am very close to real-time data capturing now and it is exactly what I've needed.
Good luck to everyone :-)
Within the StartDataProcessing I need to dequeue strings and update MANY UI controlls
No, you do not. You need to dequeue strings and then enqueue them again into the multiple queues for the different segments of the UI.
If you want to be fast, you scatter all operations and definitely the UI into separate windows that run their own separate message pumps and thus can update independently in separate UI threads.
The general process would be:
1 thread handles the serial port and takes the data and queues it.
Another one dequeues it and distributes it to separate processing threads from which
the data goes to multiple output queues all responsible for one part of the UI (depending on whether the UI Will turn a bottleneck).
There is no need to be thread safe in dequeuing. How serial is the data? Can you skip data when another update for the same piece arrives?
Read up on TPL and tasks - there are base libraries for parallel processing which come with a ton of documentation.
I have a tray icon that needs to display two icons:
If there is network connectivity, display a green circle with a check mark
If there isn't network connectivity, display a red circle with an X
So what I have is:
using System.Net.NetworkInformation;
bool isConnected = NetworkInterface.GetIsNetworkAvailable()
So I'm thinking of starting a new thread or using the background worker progress because the tray icon is a NotifyIcon which is a component so I can't use:
Form.Invoke(delegate, object[])
to update the icon property of the NotifyIcon class.
My big concern is the polling process: I could write some logic that does:
while (true)
{
System.Threading.Thread.Sleep(1000);
isConnected = NetworkInterface.GetIsNetworkAvailable();
if (isConnected)
notifyIcon.Icon = "ConnectedIcon.ico";
else
notifyIcon.Icon = "DisconnectedIcon.ico";
}
but I've seen a couple of articles that tell me to stay away from Sleep(1000). I can't seem to find those articles since I didn't bookmark them. I'm just curious to know why that isn't a good idea for polling in a thread.
You can register an Event on NetworkChange so you are being notified when the status changes:
NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
if (e.IsAvailable) {
Console.WriteLine("Network Available");
} else {
Console.WriteLine("Network Unavailable");
}
}
In you situation its totally fine to use the Sleep method.
What you saw was probably saying so its better to use a Reset Event - from looping etc...
Polling isn't always evil, but it's best avoided if possible. If I run your application that's polling once per second, that means that once per second your program is getting scheduled to do work on a CPU core that is 99.9999% going to be a no-op. On a desktop that's not too terrible, but imagine a laptop. CPUs there try run in very low power modes whenever possible, so additional CPU work means less battery life! This is the reason why many mobile platforms (iOS, Windows Phone 7, etc) ban arbitrary background threads because they know people will abuse them.
In your case, there's an easier way: just use System.Net.NetworkInformation.NetworkChange which provides events for when the network connectivity changes. No polling required!
This is an odd question, I understand. I also assumed it would be simple, because lord knows I have created my share of infinite loops.
I'm trying to cause a slight PC lag in C# - specifically I need to create a 'choppy mouse' situation system wide (not just the sandboxed exe).
The little app can't crash the computer! The lag should be able to run for 2-10 seconds ish - then stop.
What I have tried so far:
-Spawning numerous threads that save data (filled up memory and cause PF usage, no real lag).
-Spawning TONS of threads (lag at first, but then none when treads are re-spawned again - as if the second time the OS is ready).
-Spawning threads that take several screenshots (the screenshots don't seem to lag).
None of these have worked - any ideas?
Optional back story (optional):
The reason for the application, without divulging any company information, is to cover up a laggy background process in a production environment. We have tried to speed the app up, or improve the computers with no results. There is an abuse case that is present when production workers associate a lag with this background application running. The goal is to disassociate this lag ... by creating a similar one at random times sparingly.
Clarification:
The original background app is not home grown (fyi) the only real solution would to be purchase 1000s of new boxes. The company is going with the cheaper 'hide the background app' ... 'solution'. I know...
You can just create a background app that randomly calls the Windows BlockInput API at a desired interval. This allows your app to have as small a footprint as possible preventing it from taking up CPU cycles and memory.
More information here:
http://msdn.microsoft.com/en-us/library/ms646290.aspx
That said, I agree with the other posts / comments that this is addressing the symptoms and not the problem.
EDIT: code example
using System.Runtime.InteropServices;
using System.Threading;
namespace LagTimer
{
class Program
{
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool BlockInput([In, MarshalAs(UnmanagedType.Bool)] bool fBlockIt);
static void Main(string[] args)
{
Thread t = new Thread(LagTick);
t.Start();
while (true) { } // Prevent the app from exiting
}
static void LagTick()
{
while (true)
{
BlockInput(true);
System.Threading.Thread.Sleep(250);
BlockInput(false);
// TODO: Randomize time in between ticks
Thread.Sleep(100);
// TODO: Add logic for when to "sputter" the mouse
}
}
}
}
You could make a thread that has an infinite loop, and every X seconds raises an event that the UI Thread catches. The UI thread could then call Thread.Sleep for however long you want.
PLEASE DON'T DO THIS
That said, it could be accomplished by creating a number of threads that matches the number of logical processor cores in the system, set the processor affinity of each thread so that there's one per core, and then just have each thread run code like this:
int i = rand();
while (!timeLimitExpired())
{
i += rand() % i;
}
The purpose of the rand() call is to keep a compiler optimization from realizing that your loop doesn't actually do anything and optimizing it away, and the purpose of the modulo operation is to prevent creating an overflow (exception) (you could use simple division as well).
Because I don't think you should do, I won't share the code on how to determine the number of processor core or detect thread affinity. Instead, please please please fix your app. It's probably as simple as adding a sleep() call in the middle of a tight loop somewhere.
It sounds like you are trying to make a timed busy-loop. The simplest way to do that is just a tight loop that checks the clock and exits when a certian delta of time has passed.
Now, on a typical PC you might not see any "lag" when this happens. Why? Well there are a couple of reasons.
Multiple CPUs. If you don't do this on every CPU, then there's a free CPU for the OS to use and you might not notice the difference. To make sure you are using every CPU, I'd suggest creating a process to run your "cpu eater" with the CPU affinity set or CPU 0, and then another for each other CPU the system has.
Task priorities. Generally things like the desktop are given a higher priority than background tasks. If you want to keep your program from being pre-empted by that, you need to make it a very high priority.
Note: if you make your task high-priority, and then somehow set it up to run on startup or login, I am not responsible for any damage you do to your machine or OS reinstalls you are forced to perform. Also, chewing up large amounts of CPU for extended periods can cause PCs with stock cooling setups to overheat. This causes crashes and sometimes permanent damage.
I would like to add that, while we developers don't have to sign onto any code of ethics to get professional licenses like Doctors, Lawyers, and some engineers must do, there are still times when we have an obligation to refuse to carry out unethical requests.
Since you say these are your company's own machines that they are looking to slow down, that's stoopid, but not unethical. However, if these were customer machines then I'd have to put my foot down. Your boss won't thank you (and may even fire you), but your company would get absolutely roasted if/when a customer finds out what is really going on. Doing the right thing for both your company and its customers, against supervisor wishes, is what ethics is all about.
You bind a
Form2 Form = new Form2();
// open form2
Form.Show();
to a
private void timer1_Tick(object sender, EventArgs e)
//spam form2. Maybe set timer Interval to 10 or 5.
{
}
And it will lag intense within 4 min or so. atleast I can't access the task manager.
form2 properties, put opacity 0%, windowsstate = Minimized and don't show in taskbar.
this is an example:
private void timer1_Tick(object sender, EventArgs e)
//spam form2. Maybe set timer Interval to 10 or 5.
{
Form2 Form = new Form2();
// open form2
Form.Show();
}
I'm facing problem in showing FolderBrowserDialog instance created and called from a non-UI thread. It doesn't get renders properly.
Being more specific, it doesn't shows the folder tree but displays only the Make New Folder OK and Cancel
All the shell dialogs, including FolderBrowserDialog, require the COM apartment for the thread to be set to STA. You are probably missing the Thread.SetApartmentState() call:
private void button1_Click(object sender, EventArgs e) {
var t = new Thread(() => new FolderBrowserDialog().ShowDialog());
t.IsBackground = true;
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
Beware that you cannot set the owner of the dialog, it easily gets lost behind a window of another application. Which makes showing forms or dialogs on a worker thread less than a good idea.
I am not sure why you would want to do this. On a worker-thread all neccessary values for your calculation should be available. There should be no need for user-interaction to get more input.
Maybe a redesign would be more helpful in your case. Think about providing the selected folder to your worker-thread before starting it.
EDIT (reply to the comment):
If you want to do some logging my answer still applies. Your worker-thread should know where to log exceptions and not start to ask the user.
Do you use a logging framework? If not, have a look at log4net for instance. Here you normally pre-configure your logging (the log-level, path, format, ...) in a xml-file. There is no user interaction needed. Though the user could change the logging path (in the xml file).