Jade Burton wrote: > wouldn't it be great if the UI thread wasn't tagged as STA, > but rather that it was just like any old thread? This would > mean you still have a single thread dispatching events to event > handers, but your window objects would instead be written to be 100% > threadsafe and, for example, you could Move a window to a new > location by: > > myForm.Left = 77;
Hosting the UI on a non-STA thread wouldn't enable you to do that. (Or rather, it wouldn't make it any more safe than it is to do that when the UI is an STA thread.) It is possible for an HWND to be attached to a non-STA thread. This prevents you from doing various things such as hosting ActiveX controls or doing OLE Drag and Drop, but as long as you don't need anything COM-related, Win32 doesn't mandate the use of an STA thread. (This is not supported under Windows Forms though. If you try it, you will find that it sort of seems to work - last time I tried, Windows Forms didn't actually complain when I made it run a message pump on an MTA thread. However, various things don't work, and you shouldn't do it - it's not a supported mode of operation.) So you can take STA out of the picture completely for a Win32 application, and use "any old thread" as a UI thread, so long as you still pump messages on that thread. But this doesn't get you out of the whole thread affinity issue. The underlying HWND still has thread affinity. (HWND thread affinity doesn't care about COM apartments, it just cares about Win32 threads.) If there is an HWND involved, then that line of code: myForm.Left = 77; would be a threading hazard. (Specifically, it is a potential deadlock site.) This line is implicitly blocking the caller until the HWND's UI thread is able to deal with the update. (If the UI thread is blocked waiting for this thread to do something, you have deadlock.) Win32 does actually let you do just this, it just assumes that you understand the risks you are taking. (The risk of deadlock does NOT exist when doing such an operation on the UI thread itself. If you perform operations on an HWND from the UI thread, you get to bypass the message queue completely, making this a non-blocking operation.) The only way to get away from thread affinity would be to get away from HWNDs. This, incidentally, is what Avalon, the UI framework for Longhorn, is doing. There, UI components are bound to a UIContext, which is kind of like a fancy Monitor or mutex, but the UIContext doesn't have thread affinity. Any thread can enter the UIContext but only one thread can in there at a time. Once you are in the UIContext, you can use the control directly. Of course this makes all the threading hazards explicitly visible in the code, because you can see the code that enters and leaves the context clearly. This is better than hiding such hazards behind an apparently innocuous line of code such as the one you have above. But Avalon won't be with us for a while yet, so back to today's technology... The STA is really a bit of a red herring here. (Not sure if that term is popular outside of the UK. A "red herring" is something misleading - something that is presented as being part of, or even crucial to the central point, but which is in fact completely irrelevant.) The use of STA is not the cause of the threading issues. As I think has already been pointed out, it's the *result* of the threading issues. ActiveX controls have to use the STA because their UI nature means they have to deal with thread affinity, and STAs provide a way of dealing with it. But even if you avoid all things COM, the affinity requirement remains. (The STAs may have gone, but the HWND thread affinity that caused them to be needed in the first place is still there.) > to me the real problem here is that we still *have* unthreadsafe > code in the first place. > > For example, the concept of Unsafe code in C# is probably going > to be phased-out altogether at some point in the future. It's not > inconceivable to me that unthreadsafe code will also be phased out I don't see "thread unsafe code" ever going away, because there are so many different ways in which code can be unsafe for multithreaded use, and there's very little which is "thread safe" for all conceivable definitions of the term. For example, there are "thread safe" wrappers for the collection classes in .NET, but these are only "safe" in that you can call them from multiple threads without corrupting their contents. It is however dead easy to deadlock your system using these "safe" wrappers. So "safe" is a relative term here. Deadlock is really hard to eliminate - most robust concurrent systems have some kind of mechanism in place to detect it and abort any deadlocked operations because you can't usually rule it out a priori. This is because it usually emerges as a result of how a particular piece of code uses several constructs. Even if each of those individual constructs is thread safe in isolation, their use in combination may still lead to deadlock. For example, if two threads want to modify two 'thread safe' collections atomically, then if they sometimes acquire the locks on those two collections in a different order, there is a danger of deadlock occurring. (And that's an incredibly simple example. Most real systems are much more complex than that.) Each of the individual collection classes is "thread safe" in its own right, but the code that uses them also has to be thread safe. Indeed, it's usually the mechanisms used to protect data in individual objects from concurrent access (i.e. to make it "thread safe") that are also the very things that cause the deadlock! Many of the problems that emerge in Windows Forms applications when people fail to use Control.BeginInvoke or Control.Invoke (or when they use it incorrectly) are deadlock problems, often revolving around the thread affinity of UI resources. Because deadlock problems are usually a part of the whole system rather than its individual components, there's no way that Microsoft can remove all potentially thread unsafe code from the .NET framework, short of removing the ability to use multiple threads at all! Anything is thread unsafe in the right circumstances. C#'s concept of unsafe code is a very different matter, for one simple reason: it's possible to analyse code and determine unambiguously whether it's safe or unsafe, where 'safe' means conforming to the .NET Framework's type safety rules. There is no such set of rules defined anywhere for thread safety. (A fair amount of research has been done on this, but as far as I know it's a long way from being ready for use in production code, and mostly only useful in fairly simple closed systems. And in any case, you have the problem of there being so many reasonable definitions of 'thread unsafe' to choose from. An automated test that determined unambiguously whether a body of code was "thread safe" or not would be a major technological breakthrough.) -- Ian Griffiths - DevelopMentor http://www.interact-sw.co.uk/iangblog/ =================================== This list is hosted by DevelopMentorŪ http://www.develop.com Some .NET courses you may be interested in: NEW! Guerrilla ASP.NET, 17 May 2004, in Los Angeles http://www.develop.com/courses/gaspdotnetls View archives and manage your subscription(s) at http://discuss.develop.com