Threading in a Windows Service - c#

I've created an app which uses Observable Lists. I've made the ObservableList class threadsafe (I think) and it's working fine now in my application.
Now I'm trying to install my application as a service. This works fine as well, up untill the point something gets added to the list. I think the thread there just dies. I've got the following code:
/// <summary>
/// Creates a new empty ObservableList of the provided type.
/// </summary>
public ObservableList()
{
//Assign the current Dispatcher (owner of the collection)
_currentDispatcher = Dispatcher.CurrentDispatcher;
}
/// <summary>
/// Executes this action in the right thread
/// </summary>
///<param name="action">The action which should be executed</param>
private void DoDispatchedAction(Action action)
{
if (_currentDispatcher.CheckAccess())
action.Invoke();
else
_currentDispatcher.Invoke(DispatcherPriority.DataBind, action);
}
/// <summary>
/// Handles the event when a collection has changed.
/// </summary>
/// <param name="e"></param>
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
DoDispatchedAction(() => base.OnCollectionChanged(e));
}
While debugging, I've seen the Collection.Add(object) being called. It starts the DoDispatchedAction function, and the last thing the debugger hits, is _currentDispatcher.Invoke(DispatcherPriority.DataBind, action);. After this, the application continues but the code after Collection.Add(object) doesn't get executed anymore. The code which initially added the item to an ObservableList doesn't continue neither. That's why I think the Thread dies or something like that.
When checking the action in the debugger, I found out that the following message was there:
ApartmentState = '_currentDispatcher.Thread.ApartmentState' threw an
exception of type 'System.Threading.ThreadStateException'
How can I solve this problem? Am I even thinking in the right direction?

As this is a hardware dependent service, this is a little bit different from the usual LOB-style application. The difference is: the changes which should trigger events come from the backend of the application, while the whole UI framework and service architecture is intended to be used so that the frontend asks for data which the backend provides.
You could bring the two together by creating some sort of "neutral ground" where they meet.
In the hardware handling component, I would have a background thread which runs continually or runs triggered by hardware interrupts, and updates its data structures with whatever data it collects from the hardware. Then, I would have a synchronized method which can create a consistent snapshot of the hardware data at the point of time when it is called.
In the WPF client, there would be a dispatcher timer which calls this method in set intervals and updates the ObservableCollections using the data snapshots. This is possible, because it would happen on the UI thread. Actually, if possible you should try to add and remove items from the ObservableCollections, not create new collection instances, unless the data in the collection changes completely from one call to the next.
The WCF client would only be a wrapper around the method which creates data snapshots: it would only send back such a snapshot when it is called.
The WPF client for the WCF service would work as the local WPF client, only it would call the service instead of the hardware library directly, and probably I'd choose a longer interval for the DispatcherTimer, in order to avoid excessive network traffic. You could further optimize this by returning a special code which means "nothing has changed", in order to avoid sending the same data several times, or have separate methods for asking whether data has changed and retrieving the changed data.

From what I understand, you have a core code that should run as a Windows service, and a WPF application that uses the same core code.
So basically you should have something like 3 projects in your solution:
a core assembly that does some hardware-related job
an executable that will be installed as a Windows service. This executable references the core assembly
a WPF application that also references the core assembly
Dispatchers are helpful to marshall back an action to the UI thread. This is basically used to execute some code in the UI thread in WPF applications. For example, when you bind a collection to a DataGrid, the CollectionChanged event must be fired on the UI thread because it'll cause, thanks to the binding, the UI to be updated. And UI must be updated from the UI thread.
Your core assembly shouldn't have to deal with dispatchers as there is no UI to update. You could use simple Collection here, as you won't bind it to any UI component. Same for your Windows service executable.
For your WPF application, on the other hand, you could use an ObservableCollection binded on a UI component (DataGrid for example). Only in this assembly you'll have to ensure UI components are always updated from the UI thread (which means you need the Dispatcher for that).
So, a code example:
Core assembly:
public IEnumerable<SomeClass> GetHardwareInfo()
{
return new List<SomeClass> { ... };
}
Windows Service executable:
internal static void Main(string[] args)
{
...
var objs = new MyCoreInstance().GetHardwareInfo();
...
}
WPF application (let's say it's the ViewModel):
// Some UI component is binded to this collection that is obersvable
public ObservableCollection<SomeClass> MyCol
{
get
{
return this.myCol;
}
set
{
if (this.myCol != value)
{
this.myCol = value;
this.RaisePropertyChanged("MyCol");
}
}
}
public void UpdateList()
{
var info = new MyCoreInstance().GetHardwareInfo();
// Now, marshall back to the UI thread to update the collection
Application.Current.Dispatcher.Invoke(() =>
{
this.MyCol = new ObservableCollection(info);
});
}

Related

System.Diagnostics.Activity- Parent/Child relation doesnt work when using multiple Threads

I have a problem that when parent activity is started by another thread, then the main thread wont see this activity, and next Activities that supposed to be children activities that are being created in main thread, wont be added to the parent Activity that i created in another thread.
What i have:
Static definition of Sytem.Diagnostics.ActivitySource:
public static readonly ActivitySource MyActivitySource = new ActivitySource("myAppName");
Static definition of tracer provider OpenTelemetry.Trace.TraceProvider:
public static TracerProvider traceProvider;
Static definition of parentActivity:
public static Activity parentActivity;
Now how it works:
First Activity is created in another thread (with use of System.Timers.Timer), and then function is being invoked on main thread. Below code is executed only once- when parentActivity is not initialized:
parentActivity = MyActivitySource.StartActivity("CycleActivity", ActivityKind.Internal);
parentActivity.AddTag("hostname", Environment.MachineName)
parentActivity.Start();
mainForm.Invoke(new Action(() => initiateProcess()));
Then in the initiateProcess function we start child activity- and everything is working fine, i can see in logs that children activity has parent 'CycleActivity' which was created in the 4th step from another thread.
public void initiateProcess()
{
using (var subActivity= global.MyActivitySource.StartActivity("sendingTriggerToDevice"))
{
subActivity.Start();
deviceTcp.Send("Trigger");
subActivity.Stop();
}
}
The problem occurs when in the next step, which consist of waiting for the data to come from deviceTcp.
I have defined callback function, that is being run when deviceTcp send data to my application.
And im creating activity inside that function and the body looks like:
public void deviceTcpMessageReceived(string data)
{
using (var subActivity = global.MyActivitySource.StartActivity("deviceTcpMessageReceived"))
{
subActivity.Start();
//.... additional stuff
}
parentActivity.Stop();
}
Parent activity which has been started in the 4th step is not being stopped in the meantime.
I know that deviceTcpMessageReceived was run, and everything worked fine, except that activity created in callback named deviceTcpMessageReceived was not wired to the parent activity.
Summary
Any ideas, why the parent Activity is only visible by MyActivitySource when i synchronously Invoke a call (from subthread) of initiateProcesson the main thread, and it is not visible, when message from device is comming, and callback function deviceTcpMessageReceived is being ran on the Main thread?
I have read in the documentation System.Diagnostics.Activity that I can set an ActivityKind when i start new Activity that:
By default, all new Activities are set to Internal, which is
appropriate for Activities that are an internal operation within an
application with no remote parent or children.
But i have no idea what Activity Kind i should use. IMO they shouldnt impact relationship behaviour between parent/children activities. (And they clearly dont do it, when you look at 4 and 5th step that i described).
Also the parent activity from the subthread is not closed (there is no using, or Stop being called in the meantime), until we successfully receive data from deviceTcp, so i dont understand why Activity created in the 6th has no parent.
Any help or suggestion is welcome.
If Activities are not in the same scope, they might not wire up to each other.
To solve your problem you have to set up Parent Activity in your callback function.
If you want to wire up callback event to the Cycle Activity you have to call SetParentId method to wire up your callback Activity, your code could look like this:
public void deviceTcpMessageReceived(string data)
{
using (var subActivity = global.MyActivitySource.StartActivity("deviceTcpMessageReceived"))
{
subActivity.SetParentId(parentActivity.TraceId, parentActivity.SpanId);
subActivity.Start();
//.... additional stuff
}
parentActivity.Stop();
}

Checking that async data load compete before accessing data

I'm using MVVMlight SimpleIoC container, particularly to store quite a large volume of data, which is accessible throughout the application. When the application is started, I launch an asynchronous process, which prepares the data.
private MethodOfOriginalThread()
{
(new Thread(this.LoadRegistry)).Start();
}
private void LoadRegistry()
{
int meetingId = SimpleIoc.Default.GetInstance<MeetingDetails>().MeetingId;
List<Shareholder> registry = this.dataService.SearchRegistry(meetingId, string.Empty);
SimpleIoc.Default.Register(() => registry);
}
The process of obtaining the data takes approximately 10 seconds. After the process is complete, I save the data to container, as seen in the code above.
Later from a different viewModel I'm accessing this data:
this.shareholders =
new NotifyObservableCollection<Shareholder>(
SimpleIoc.Default.GetInstance<List<Shareholder>>()
);
The problem arises when this access is made before the actual load completes. Since the viemodels are very loosely coupled, I cannot refer to one from another. Sending messages may result in hyge amount of code, since these results are widely used in the application, and each viewmodel should have the message handling code. How can I check and wait, whether the data has been successfully loaded? An endless loop, which waits for required object in the container, sounds halfway ok, since the operation should eventually be completed, but I'm worried that this is not the most elegant solution. And also I need to let the user have some feedback that the data is still being loaded, so he waits patiently, and does not press too many buttons. This is quite challenging with an endless loop and frozen application.

Debugging/profiling/optimizing C# Windows service in VS 2012

I am creating a Windows service in C#. Its purpose is to consume info from a feed on the Internet. I get the data by using zeromq's pub/sub architecture (my service is a subscriber only). To debug the service I "host" it in a WPF control panel. This allows me to start, run, and stop the service without having to install it. The problem I am seeing is that when I call my stop method it appears as though the service continues to write to the database. I know this because I put a Debug.WriteLine() where the writing occurs.
More info on the service:
I am attempting to construct my service in a fashion that allows it to write to the database asynchronously. This is accomplished by using a combination of threads and the ThreadPool.
public void StartDataReceiver() // Entry point to service from WPF host
{
// setup zmq subscriber socket
receiverThread = new Tread(SpawnReceivers);
receiverThread.Start();
}
internal void SpawnReceivers()
{
while(!stopEvent.WaitOne(0))
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessReceivedData), subscriber.Recv()); // subscriber.Recv() blocks when there is no data to receive (according to the zmq docs) so this loop should remain under control, and threads only created in the pool when there is data to process.
}
}
internal void ProcessReceivedData(Object recvdData)
{
// cast recvdData from object -> byte[]
// convert byte[] -> JSON string
// deserialize JSON -> MyData
using (MyDataEntities context = new MyDataEntities())
{
// build up EF model object
Debug.WriteLine("Write obj to db...");
context.MyDatas.Add(myEFModel);
context.SaveChanges();
}
}
internal void QData(Object recvdData)
{
Debug.WriteLine("Queued obj in queue...");
q.Enqueue((byte[])recvdData);
}
public void StopDataReceiver()
{
stopEvent.Set();
receiverThread.Join();
subscriber.Dispose();
zmqContext.Dispose();
stopEvent.Reset();
}
The above code are the methods that I am concerned with. When I debug the WPF host, and the method ProcessReceivedData is set to be queued in the thread pool everything seems to work as expected, until I stop the service by calling StopDataReceiver. As far as I can tell the thread pool never queues any more threads (I checked this by placing a break point on that line), but I continue to see "Write obj to db..." in the output window and when I 'Break All' in the debugger a little green arrow appears on the context.SaveChanges(); line indicating that is where execution is currently halted. When I test some more, and have the thread pool queue up the method QData everything seems to work as expected. I see "Queued obj in queue..." messages in the output window until I stop the service. Once I do no more messages in the output window.
TL;DR:
I don't know how to determine if the Entity Framework is just slowing things way down and the messages I am seeing are just the thread pool clearing its backlog of work items, or if there is something larger at play. How do I go about solving something like this?
Would a better solution be to queue the incoming JSON strings as byte[] like I do in the QData method then have the thread pool queue up a different method to work on clearing the queue. I feel that that solution will only shift the problem around and not actually solve it.
Could another solution be to write a new service dedicated to clearing that queue? The problem I see with writing another service would be that I would probably have to use WCF (or possibly zmq) to communicate between the two services which would obviously add overhead and possibly become less performant.
I see the critical section in all of this being the part of getting the data off the wire fast enough because the publisher I am subscribed to is set to begin discarding messages if my subscriber can't keep up.

Exception only occuring on DragDrop

I have a WinForms application that makes use of a TaskDialog library that leverages the Vista style dialogs from ComCtl32.dll and for lesser OS's it uses an emulated win form...
But that's not the problem... This library works fine and we've never had issues with it. Until now... In deed if we launch a dialog under normal circumstances, then it looks fine.
However, I've added a drag-drop handler on my main form to capture file paths dropped from other sources (say Windows Explorer). If that drag-drop handler is the first time the dialog has been shown then we get the following exception:
Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32'.
This occurs on the third party library's call to:
/// <summary>
/// TaskDialogIndirect taken from commctl.h
/// </summary>
/// <param name="pTaskConfig">All the parameters about the Task Dialog to Show.</param>
/// <param name="pnButton">The push button pressed.</param>
/// <param name="pnRadioButton">The radio button that was selected.</param>
/// <param name="pfVerificationFlagChecked">The state of the verification checkbox on dismiss of the Task Dialog.</param>
[DllImport ( "ComCtl32", CharSet = CharSet.Unicode, PreserveSig = false )]
internal static extern void TaskDialogIndirect (
[In] ref TASKDIALOGCONFIG pTaskConfig,
[Out] out int pnButton,
[Out] out int pnRadioButton,
[Out] out bool pfVerificationFlagChecked );
If a dialog has already been shown, then the handler will run OK.
The DragDrop handler for the form does not show InvokeRequired and but I was careful to raise the dialog via Form.Invoke anyway.
private void MainForm_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
Array fileNames = (Array)e.Data.GetData(DataFormats.FileDrop);
if (fileNames != null && fileNames.OfType<string>().Any())
{
foreach (var fileName in fileNames.OfType<string>())
{
this.Invoke(new Action<string>(this.AttemptOpenFromPath), fileName);
}
}
}
}
As a side: I am compiling (and running) it on a 64-bit, Windows 7 machine but with the "AnyCPU" architecture flag.
Any thoughts/solutions as to why the exception is only raised when the first call to TaskDialogIndirect is via the DragDrop handler???
[DllImport ( "ComCtl32", ...)]
The library is taking a pretty heavy shortcut to use the comctl32.dll Windows dll. This tends to come to a good end by accident, but it falls over in your code. The full explanation is rather long-winded, I'll try to keep it short.
The core problem is that Windows has two versions of comctl32.dll. The one in c:\windows\system32 is a legacy version, implementing the common controls the way they looked and worked back in Windows 2000 and earlier. Windows XP acquired visual styles, making those controls look very different. There's another DLL that implements those visual styles, it is stored in the Windows side-by-side cache (c:\windows\winsxs).
An application must explicitly tell Windows that it supports the new version of the DLL. There are two ways to do it, you can do so in a manifest (the way WPF does it) or you can make an operating system call, the CreateActCtx() function (the way Winforms does it).
The way the library works is that it hopes that somebody has done one of those two things. And loaded the correct version of comctl32.dll so that pinvoking the [DllImport] function doesn't actually load the c:\windows\system32 version. The old one that doesn't implement TaskDialogIndirect(). This works by accident because some code usually does. And the fact that Windows only cares about the DLL name and not where it came from to determine if it needs to load a DLL.
I can somewhat guess how you ran out of luck. You are using Control.Invoke(), something you only ever need to do when you are using threads. Clearly you are displaying this form on another thread, not the main UI thread. This is in general a Really Bad Idea, the UI thread was already designed to be able to handle multiple windows. The one thing that didn't happen that normally happens on the UI thread is the Application.EnableVisualStyles() call. The one that tells Windows that you want the new version of comctl32.
You can try calling it on your worker thread. Might work, no idea. By far the best solution is to not create windows on worker threads. You can get rid of the wonky library by using the Windows API Code Pack, it provides a wrapper for task dialogs.
It turned out that within the DragDrop handler, I should be using BeginInvoke to asynchronously queue the call onto the Form's UI thread as opposed to synchronously waiting for it to complete within the handler...
Therefore, it was resolved with:
private void MainForm_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
Array fileNames = (Array)e.Data.GetData(DataFormats.FileDrop);
if (fileNames != null && fileNames.OfType<string>().Any())
{
foreach (var fileName in fileNames.OfType<string>())
{
this.BeginInvoke(new Action<string>(this.AttemptOpenFromPath), fileName);
}
}
}
}
I'm not sure why though!?? Can a commenter perhaps provide a reason?

Message Pumps and AppDomains

I have a a C# (FFx 3.5) application that loads DLLs as plug-ins. These plug-ins are loaded in separate AppDomains (for lots of good reasons, and this architecture cannot change). This is all well and good.
I now have a requirement to show a Dialog from one of those plug-ins. Bear in mind that I cannot return the dialog Form to the main application and have it displayed there (the current infrastructure doesn't support it).
Failure 1
In my DLL I created a Form and called Show. The dialog outline showed up but did not paint and it doesn't respond to mouse events. I assumed that this is becasue the DLL is in a separate AppDomain and the message pump for the app is somehow unable to dispatch messages to the new Form.
Failure 2
In my DLL I created a Form and called ShowDialog, which by all rights should create an internal message pump for the dialog.. The dialog is displayed and responded to clicks (hooray), but it appears that the primary app no longer is processing or dispatching windows messages because it quits painting and no longer responds to mouse events. For some reason now it seems that the main app's message pump is not dispatching.
Failure 3
In my DLL I created a Form and called Application.Run. This will certainly create a complete second message pump. I get the same behavior as Failure 2 - the Dialog behaves, but the calling app does not.
Any thoughts on what exactly is going on here and how I might go about showing a dialog from the other AppDomain's DLL and have both the caller and the callee still respond and paint properly?
Try using appdomain1's main form's BeginInvoke with a delegate that displays the form from appdomain2. So in Pseudocode:
Appdomain1:
AppDomain2.DoSomething(myMainForm);
AppDomain2:
DoSomething(Form parent)
{
Form foolishForm = new Form();
parent.BeginInvoke(new Action( delegate { foolishForm.Show(); } ));
}
The code may not be perfect, but it demonstrates the concept.
By the way, if you are having problems passing forms around because of remoting you can:
public class Container<T> : MarshalByRefObject
{
private T _value;
public T Value { get { return _value; } set { _value = value; } }
public Container() { }
public Container(T value) { Value = value; }
public static implicit operator T(Container<T> container)
{
return container.Value;
}
}
That will contain object you throw at it.
We have a very similarly architected application that loads DLL files and plugins. Each DLL file is loaded in a separate application domain, which is created on a separate thread. We have a third-party control in a form that would not appear unless we call System.Windows.Forms.Application.DoEvents() regularly.
Pseudo code:
<In new thread>
<Application domain created. Start called inside new application domain.>
<Start loads new DLL file, calls init function in DLL file>
<Start loops, calling DoEvents until the DLL file exits>
<Application domain unloaded>
<Thread exits>
This solved all of our GUI issues.
One thing that I've used before is implementing a DomainManager. It's possible to customize the various application domain security/binding/context's to handle complex or chicken-egg type problems with respect to pumping your data where you want ;)
I've ususally done this from a native.exe, bootstrapping the CLR through the COM interfaces (psudo code but the order and method names are correct ;):
CorBindToRuntimeEx()
SetHostControl()
GetCLRControl()
SetAppDomainManagerType("yourdomainmanger","info")
// Domain manager set before starting runtime
Start()
HostControl -- GetDomainManagerForDefaultDomain()
DomainManager -- Run()
Your domain manager can be any CLR class library, so their's not that much more native C.
A side note, if you were in WPF; I really like using the "Microsoft.DwayneNeed.Controls" method. Where you may have disperate threads with their own Dispatcher pump in the same UI control (not needing to resort to entirely new Window()'s).
The unique thing about using this approach, is that even if the primary UI thread is blocked/busy (some heavy operation, scanning the filesystem, etc...), these other threads may paint/update their UIElement's without any hiccup.

Categories