Archived

This forum has been archived. Please start a new discussion on GitHub.

Create C# threads as background threads?

Hello,

We are using Ice to implement a number of services which are used by a number of financial applications. The libraries that these applications use do not directly expose any Ice objects, so the applications are unaware that Ice is being used under the hood. In particular, they are not directly creating a Communicator, and are therefore not directly calling destroy() on it.

One problem that we have run into in c# is that because the threads created by Ice are created as foreground threads (the default), they will not permit the application to exit, even if the main thread exits. We therefore have had to jump through some hoops to make sure that each app explicitly does a bunch of cleanup work, which can be easily forgotten.

Would you see any problems with setting the threads that Ice creates to be background threads (Thread.IsBackground = true), to prevent them from keeping the app alive once the main thread terminates?

Thanks,
Brett

Comments

  • Thanks for the suggestion. I will try this. I don't anticipate a problem, because user code is required to call Communicator::destroy() before it exits, at which point the Ice run time joins with all outstanding threads. But better be safe than sorry... ;)

    Cheers,

    Michi.
  • Thanks for trying this out. As you mentioned, the app should call Communicator::destroy(), but failure to do so shouldn't cause the app to hang.

    It's especially problematic in GUI apps, where the user closes the main window and thinks the app is dead, when in fact it is still running, but just isn't visible.

    Thanks again,
    Brett
  • Note that there might be other foreground threads from other libraries or from our own application that can prevent the application from terminating. If you really want to terminate a C# application non-gracefully, why not use Process.Kill()?
  • Hi Marc,

    I'm not looking to kill the app non-gracefully. I'm just looking to have it exit normally, by returning from Main(). Ideally everything would be properly destroyed(), but I don't consider not doing it non-graceful. Maybe it's my Unix/C++ background, but I feel that when an app returns from main() it should be dead, whether or not all of the proper shutdown methods have been called.

    Clearly other libraries could have created foreground threads as well. When I find them, I'll email their authors as well. :-)

    Thanks,
    Brett
  • As far as Ice is concerned, if you do not call destroy() on the communicator, the application does not shut down gracefully. This might or might not matter for your application, but to be on the safe side, I highly recommend to call destroy() on the communicator instead of just terminating the application.

    If you use Ice for C++, you must call destroy() on the communicator, otherwise bad things will happen (such as crashes on shutdown). The behavior of C++ applications is completely undefined if you return from main() without first joining with all other threads. Calling destroy() on the communicator takes care of this.
  • I completely agree that all apps, whether C# or C++, should call destroy(), and that failure to do so is a bug. All I am saying is that the penalty for such a bug should be abrupt termination, possibly resulting in a crash. The current behavior in C# of keeping the process alive with no means of killing it besides finding it on the Processes tab of Task Manager (it won't even show up under Applications or the Taskbar), serves no benefit. At least with a crash, it is immediately obvious that something went wrong, and our users can immediately inform the developers. I just don't see any downside to setting the threads to be background threads. It will have no effect on well behaved apps, but it will prevent ill-behaved apps from consuming system resources.

    On a related note, would it be possible to have Communicator implement IDisposable (where Dispose() calls destroy()), so that it can integrate more seamlessly with the standard cleanup mechanisms that C# and its libraries provide?

    Thanks again,
    Brett
  • bpolivka wrote: »
    On a related note, would it be possible to have Communicator implement IDisposable (where Dispose() calls destroy()), so that it can integrate more seamlessly with the standard cleanup mechanisms that C# and its libraries provide?

    Hmmm... Doing this would be possible. I guess this would be one way to ensure that, if an application calls Exit(), Communicator.destroy() will actually be called. I'll have a look at this--I'm not sure I can see all the consequences just yet...

    Cheers,

    Michi.
  • It still wouldn't be automatically cleaned up at exit(), but it would allow Communicators to integrate with a lot of the component management frameworks (Windsor, Spring, System.ComponentModel, etc.) that are out there. They all allow an app to construct a container of components, and destroy them all at shutdown by Destroy()ing the container. If the components implement IDisposable, their respective Destroy() members will be called.

    We are currently using a container like this, along with a wrapper around a Communicator, to allow libraries to register components that the app needs to dispose of at shutdown. If Communicator implemented IDisposable directly, we wouldn't need the wrapper.

    Thanks,
    Brett
  • No, not good. Marc just pointed out that calling Exit() from within an operation implementation would cause deadlock if we do this.

    Michi.
  • What isn't good? Creating threads as background threads, or implementing IDisposable?

    I can't imagine why implementing IDisposable would cause deadlock. Calling Exit() will not automatically call Dispose(). The app still has to take explicit action to make that happen.
  • Implementing IDisposable isn't good. The run time will finalize on exit and call Dispose() if the application hasn't done that yet. If Exit() is called from within an operation implementation in a server, that would cause deadlock, as far as I can see.

    Cheers,

    Michi.
  • Not to continue to drag this out, but the runtime may run finalizers at Exit(), but it will not automatically call Dispose(). Something has to take explicit action for Dispose() to be called. If you run the following example, you will see that the finalizer is called, but Dispose() never is:

    using System;

    namespace DisposeTest
    {
    class Junk : IDisposable
    {
    public Junk()
    {
    }

    ~Junk()
    {
    Console.WriteLine("Finalizer called");
    }

    public void Dispose()
    {
    Console.WriteLine("In Dispose()");
    }
    }

    class Program
    {
    static void Main(string[] args)
    {
    Junk junk = new Junk();
    Environment.Exit(1);
    }
    }
    }


    I don't mean to be annoying, and I really appriciate the time you guys have spent responding to this issue. If you don't want to implement either of the ideas discussed in this thread, I completely respect your decision. I just wanted to share some minor pain points I have encountered while using your excellent framework, and suggest some ideas.

    Thank you for all of your time, and keep up the great work!!

    Thanks,
    Brett
  • bpolivka wrote: »
    Not to continue to drag this out, but the runtime may run finalizers at Exit(), but it will not automatically call Dispose(). Something has to take explicit action for Dispose() to be called.

    Oops, yes, you are right. It's not clear to me what adding a Dispose() method would achieve then though. In effect, it would just be an alias for Communicator.destroy(). Who would call the Dispose() method (if not the application)? Or, to put it differently, if the application doesn't call destroy(), would it be any more likely to call Dispose?
    I don't mean to be annoying, and I really appriciate the time you guys have spent responding to this issue. If you don't want to implement either of the ideas discussed in this thread, I completely respect your decision. I just wanted to share some minor pain points I have encountered while using your excellent framework, and suggest some ideas.

    No, you are not annoying at all. Feedback like yours is important--without it, we'd be continuing to develop in ignorance! (See my editorial in Issue 18 of Connections.)

    Cheers,

    Michi.
  • "Oops, yes, you are right. It's not clear to me what adding a Dispose() method would achieve then though. In effect, it would just be an alias for Communicator.destroy(). Who would call the Dispose() method (if not the application)? Or, to put it differently, if the application doesn't call destroy(), would it be any more likely to call Dispose?"

    Even the application forgets to call Dispose, the communicator's finalizer code will call Dispose() subject to some boolean checks.
  • The advantage of having a Dispose() method would be that there are a lot of component management frameworks that can take advantage of IDisposable objects.

    As I mentioned above, our libraries don't expose Ice directly to the client applications. Many of the apps were initially built as fat clients, and are being migrated to a service-based architecture, so we are trying to integrate Ice with as little impact on the clients as possible. One way we have achived this is by using a component container such as the Windsor MicroKernel (www.castleproject.org) to allow different subsystems to create and register components in a container which is under the application's control. The application doesn't know what is in the container. It just knows that before it exits, it has to Dispose() of the container, which in turn will Dispose() of any IDisposable objects inside of itself. Each of these libraries that uses Ice retrieves its Communicator from the container (the container can be configured to create it on first request), and the Communicator gets destroyed when the app Dispose()s of the container.

    However, due to the fact that Communicator doesn't implement IDisposable, it can't directly take advantage of this. We have to wrap it in a thin wrapper class that does implement IDisposable, which in turn calls calls destroy(). If Communicator implement IDisposable directly, we wouldn't need this wrapper class.

    The lack of IDisposable is far from a showstopper and not a big deal at all. It is just a very minor inconvenience.

    Thanks,
    Brett
  • rdilipk wrote: »
    "Oops, yes, you are right. It's not clear to me what adding a Dispose() method would achieve then though. In effect, it would just be an alias for Communicator.destroy(). Who would call the Dispose() method (if not the application)? Or, to put it differently, if the application doesn't call destroy(), would it be any more likely to call Dispose?"

    Even the application forgets to call Dispose, the communicator's finalizer code will call Dispose() subject to some boolean checks.

    Only if the finalizer was coded to call Dispose(), which is not a requirement.
  • On balance, I think that adding a Dispose() to the communicator isn't worth it. Because much of the Communicator code is generated from Slice, the only way to add this would be to add another metadata directive. And the payback for the effort is too small to make this worthwhile, I think. As you say, it's easy enough to create a wrapper class for those application that want to hide the Ice run time entirely.

    Cheers,

    Michi.
  • I hadn't thought about the fact that the Communicator was generated from Slice. I totally agree that it's not worth adding a metadata directive just to get this feature.

    Thanks for all of your time,
    Brett
  • For Ice for C#/VB 3.2, the Ice run time threads will be created as background threads.

    Cheers,

    Michi.