- Posts: 18
- Joined: Sun Jun 07, 2015 4:07 am
I have the weirdest problem. Here is the setup:
We have been developing some software for use at certain live amateur sporting events. The software tracks teams and scores and winners and things like that. The software can also control an ATEM Television Studio to do things like automatically generate a still image and display it (like a leaderboard) or switch to a live input of the competition or even display a sponsor graphic... It's basically designed to let the event administrator focus on running the event and let the software automate the display of relevant information via the ATEM.
I had some trouble working with the Switcher SDK 6.x from C#, but eventually things settled down enough that I made progress. However, I had some problems with threading, COM and .NET that I never really solved. Specifically, if I create the switcher object on my UI thread, I can't use it from background threads. Any attempt to access the "CreateIterator" method from a background thread would cause QueryInterface errors and fail. Also, some event callbacks/messages like 'bmdSwitcherMediaPoolEventTypeTransferCompleted' happen in a different thread context and don't seem to work properly from a UI thread. (Here is a link to my original exchange with Nicholas Gill regarding this issue: viewtopic.php?f=12&t=36252).
So after some tinkering I came up with a way of making sure I create and access the Switcher object only from an MTA thread. Which not only avoided possible deadlock issues when constantly dispatching to my UI thread, but also fixed my callback/message problems, and generally made life much easier for long running tasks. But my solution came at a price. For some, completely inexplicable reason my application wil crash exactly 15 minutes after I launch it.
I know how it sounds. I must be doing something wrong.
At the time, I didn't have the bandwidth to properly dig into the issue and as a temporary hack I discovered that if I simply disconnected and reconnected the switcher in code every 10 minutes or so, I could avoid the issue. Not my most elegant hack, but it got me through.
Now I am re-visiting the issue, and was able to distill the issue down to a very small code block that replicates the problem. I created a WPF application in Visual Studio 2015 running on Windows 10 and referenced the BMDSwitcher.dll. Here is my code behind:
All I have to do is run that code and start my stopwatch and let the app idle for 15 minutes and it will crash. Blammo. Can anyone shed any light on why this might be so? Am I committing some unforgivable sin by creating my switcher inside the MTA thread? If I don't create the switcher inside the MTA thread, how can it be used without dispatching everything to the UI thread? If you are supposed to dispatch everything to the UI thread, then how do I reconcile Nicholas comments last year to use an MTA thread?
I feel like I am missing something important here.
A few final thoughts:
First, I know my real application will exhibit the 15 minute crash on multiple computers. I have not tested the above code on multiple computers. Based on the behavior of my real app, I am going to go out on a limb and say it is not environmental.
Second, I know in the code above I am not holding a reference to the Thread object, so I would assume after the thread completes it must undergo some kind of garbage collection at some point? But holding a reference to the thread did not impact my problem. I also tried invoking DisableComObjectEagerCleanup() before starting the thread but it also did not help.
Third, please realize, my real code is quite a bit more complex. This is simply a boiled down example of how to exhibit the problem. I find that being able to work with the switcher from multiple background threads is preferable to trying to dispatch everything back to the UI.
Fourth, I am also aware that when dealing with multiple threads I have to manage thread access to the physical switcher to avoid multiple threads trying to perform conflicting operations at the same time. I have gatekeeper logic to avoid these kinds of problems.
Any and All suggestions/input/help is appreciated.
Geo...
We have been developing some software for use at certain live amateur sporting events. The software tracks teams and scores and winners and things like that. The software can also control an ATEM Television Studio to do things like automatically generate a still image and display it (like a leaderboard) or switch to a live input of the competition or even display a sponsor graphic... It's basically designed to let the event administrator focus on running the event and let the software automate the display of relevant information via the ATEM.
I had some trouble working with the Switcher SDK 6.x from C#, but eventually things settled down enough that I made progress. However, I had some problems with threading, COM and .NET that I never really solved. Specifically, if I create the switcher object on my UI thread, I can't use it from background threads. Any attempt to access the "CreateIterator" method from a background thread would cause QueryInterface errors and fail. Also, some event callbacks/messages like 'bmdSwitcherMediaPoolEventTypeTransferCompleted' happen in a different thread context and don't seem to work properly from a UI thread. (Here is a link to my original exchange with Nicholas Gill regarding this issue: viewtopic.php?f=12&t=36252).
So after some tinkering I came up with a way of making sure I create and access the Switcher object only from an MTA thread. Which not only avoided possible deadlock issues when constantly dispatching to my UI thread, but also fixed my callback/message problems, and generally made life much easier for long running tasks. But my solution came at a price. For some, completely inexplicable reason my application wil crash exactly 15 minutes after I launch it.
I know how it sounds. I must be doing something wrong.
At the time, I didn't have the bandwidth to properly dig into the issue and as a temporary hack I discovered that if I simply disconnected and reconnected the switcher in code every 10 minutes or so, I could avoid the issue. Not my most elegant hack, but it got me through.
Now I am re-visiting the issue, and was able to distill the issue down to a very small code block that replicates the problem. I created a WPF application in Visual Studio 2015 running on Windows 10 and referenced the BMDSwitcher.dll. Here is my code behind:
- Code: Select all
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using BMDSwitcherAPI;
namespace SwitcherBomb
{
public partial class MainWindow : Window
{
private IBMDSwitcher m_objSwitcher = null;
public MainWindow()
{
InitializeComponent();
}
private void OnClick(object sender, RoutedEventArgs e)
{
var taskCompletionSource = new TaskCompletionSource<object>();
var thread = new Thread(() =>
{
try
{
string szAddress = "192.168.1.240";
m_objSwitcher = null;
IBMDSwitcherDiscovery objSwitcherDiscovery = new CBMDSwitcherDiscovery();
_BMDSwitcherConnectToFailure objFailureReason = 0;
try
{
IBMDSwitcher objLocalSwitcher = null;
objSwitcherDiscovery.ConnectTo(szAddress, out objLocalSwitcher, out objFailureReason);
if (objLocalSwitcher is IBMDSwitcher)
{
m_objSwitcher = objLocalSwitcher;
}
}
catch (System.Runtime.InteropServices.COMException)
{
System.Diagnostics.Debug.WriteLine("Connect failed: {0}", objFailureReason);
}
taskCompletionSource.SetResult(null);
}
catch (Exception ex)
{
taskCompletionSource.SetException(ex);
}
});
thread.SetApartmentState(ApartmentState.MTA);
thread.Start();
taskCompletionSource.Task.Wait();
if (m_objSwitcher is IBMDSwitcher)
{
System.Diagnostics.Debug.WriteLine("WooHoo! Switcher connected!");
}
}
}
}
All I have to do is run that code and start my stopwatch and let the app idle for 15 minutes and it will crash. Blammo. Can anyone shed any light on why this might be so? Am I committing some unforgivable sin by creating my switcher inside the MTA thread? If I don't create the switcher inside the MTA thread, how can it be used without dispatching everything to the UI thread? If you are supposed to dispatch everything to the UI thread, then how do I reconcile Nicholas comments last year to use an MTA thread?
I feel like I am missing something important here.
A few final thoughts:
First, I know my real application will exhibit the 15 minute crash on multiple computers. I have not tested the above code on multiple computers. Based on the behavior of my real app, I am going to go out on a limb and say it is not environmental.
Second, I know in the code above I am not holding a reference to the Thread object, so I would assume after the thread completes it must undergo some kind of garbage collection at some point? But holding a reference to the thread did not impact my problem. I also tried invoking DisableComObjectEagerCleanup() before starting the thread but it also did not help.
Third, please realize, my real code is quite a bit more complex. This is simply a boiled down example of how to exhibit the problem. I find that being able to work with the switcher from multiple background threads is preferable to trying to dispatch everything back to the UI.
Fourth, I am also aware that when dealing with multiple threads I have to manage thread access to the physical switcher to avoid multiple threads trying to perform conflicting operations at the same time. I have gatekeeper logic to avoid these kinds of problems.
Any and All suggestions/input/help is appreciated.
Geo...