0

In my program, the main function starts a background thread which creates an object that I need in the UI thread (uses Windows Forms, thus marked [STAThread]).

Simplified code:

internal static MyDependencyInjectionKernel kernel;
internal static readonly object kernelLock = new object();
internal static AutoResetEvent kernelReadyEvent = new AutoResetEvent(false);

private static void BackgroundThread()
{
    kernel = new MyDependencyInjectionKernel();
    kernel.Inject(this);
    kernelReadyEvent.Set();
}

[STAThread]
public static void Main(string[] args)
{
    var backgroundThread = new Thread(new ThreadStart(BackgroundThread));
    backgroundThread.IsBackground = true;
    backgroundThread.Start();

    // Wait for background thread to create the object
    bool res = kernelReadyEvent.WaitOne();

    lock(kernelLock)
        Debug.Assert(kernel != null);

    // ...

    // Background thread still running here and doing other things (unimportant)
    Application.Run(new MainForm()); // <-- MainForm wants to use "kernel" field
}

However, res becomes false and the field kernel remains null in the main thread, even if I set a breakpoint at the lock statement. Also, using Thread.Sleep in the Main function would return immediately, without sleeping.

So it seems to me that probably [STAThread] puts restrictions to these methods?! Is that true, and what is a good way to circumvent this? In my case, I could probably mark the main thread as non-STA and then run an STA thread later on (did not try that yet), but is there a general solution?

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
AndiDog
  • 68,631
  • 21
  • 159
  • 205
  • Why don't you use `backgroundThread.Join()`? – SLaks Sep 08 '13 at 20:59
  • When you're asking main thread to wait for background operation to finish, why do you need a `Background` thread at all? Why not do it in `MainThread` itself? – Sriram Sakthivel Sep 08 '13 at 21:03
  • 1
    This is very difficult to explain. Blocking an STA thread is certainly illegal, but the CLR lets you get away with using WaitOne(). It will pump a message loop on behalf of the STA thread, required to fulfill the single-threaded apartment contract. It will reject a WaitAll(), but that produces an exception. "Inject" sounds like a very creepy name, maybe it does as much damage as the name promises. Notably there is no point at all in using a worker thread, if an MTA is required for some mysterious reason then there's a whole lot more than we can't see. – Hans Passant Sep 08 '13 at 21:15
  • @SLaks: Simplified code, only posted the relevant code ;) – AndiDog Sep 08 '13 at 21:15
  • @Sriram: The background thread keeps running while the UI is displayed, I only need one shared variable (dependency injection kernel) that is created when the background thread starts. – AndiDog Sep 08 '13 at 21:16
  • But your code doesn't show the form till BackgroundThread finishes. Mock it as like you have in reality to help us to view the same picture you see. – Sriram Sakthivel Sep 08 '13 at 21:24
  • The form does *not* wait for the background thread, there's no `Join()` in the code. Added some comments to make it more clear. I believe the problem is how to synchronize a normal thread with a STAThread in order to access the same static field. – AndiDog Sep 09 '13 at 06:57

0 Answers0