-1

Context

A WPF UI has a user control that use COMs and DirectShow.NET. The WPF UI display the time used to transform a video frame.

I declare a float in the WPF UI. The float is passed by reference to my COM filter. The COM filter increments the float, each time a frame is transformed.

A timer is used to display the float to the screen every x mili seconds.

Also, keep in mind that multiple frames are modified per second, which means that the float is written multiple time per second. This is why I decided to not go with events and go with a reference float instead.

Problem

The same float is being read and written by two different threads, which cause a crash. The faster the read timer, the faster the crash occurs... for obvious reasons.

Question

Do I need to somehow lock the float in both threads ? If so, how ?

If possible, I want to keep the float a simple variable, not make it a property and not make it a class member. ( else it would require multiple changes in my COM, but I will do it if it's the only way. )

PS: I've read MultiThreading COMObject and UI Thread (C#) but couldn't understand it and not sure if it applies to my case.

Community
  • 1
  • 1
Dave
  • 2,774
  • 4
  • 36
  • 52
  • You might wan't to read: http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx . just place a lock around your set and get of your float and it should prevent more then one thread accessing it simultaneously. – Nick Otten Oct 15 '14 at 14:53
  • Also, don't forget that .NET is allowed to move the objects in memory. The address you passed doesn't necessarily still point to the float. In fact, for newly created objects, it's almost guaranteed that they will move on the next heap compaction. – Luaan Oct 15 '14 at 15:11
  • @Luaan That's very interesting and I think it actually occurs. Sometimes it just crash but sometimes the app still runs but the floats are not incremented anymore. I think you pointed out at my #2 problem. How do I prevent that/ go around it ? – Dave Oct 15 '14 at 15:13
  • @downvoter , care to comment and help find a better solution ? – Dave Oct 15 '14 at 15:14
  • Well, you generally don't want to pass addresses of .NET memory anywhere. If you only need it for a limited time, you can use the `fixed` keyword (which you're probably doing), but it only pins the address for the `fixed` scope. If you really need it for a longer time, you can create a `GCHandle.Alloc(value, GCHandleType.Pinned)` , store that and use that address, but it's likely going to harm the GC performance. The best option in your case may be to simply allocate some unmanaged memory which the COM object will refer to, and explicitly copy it to your managed variable using `Marshal`. – Luaan Oct 15 '14 at 15:21

1 Answers1

0

Luaan said in the comments,

Also, don't forget that .NET is allowed to move the objects in memory. The address you passed doesn't necessarily still point to the float. In fact, for newly created objects, it's almost guaranteed that they will move on the next heap compaction.

This made me realise that it is wrong to pass variables by reference from C# to a C++ COM, for a long process.

Instead of sending my variables by reference for a long process ( about a minute ), I call the method every second with the variables passed by reference to get samples of the values.

Also, the COM writes all the values to a file. So I can compute the exact sum at the end.

Doing so removed the COM errors of writing to a float that has been moved by heap compaction.

Dave
  • 2,774
  • 4
  • 36
  • 52