TheSilverHammer said:
If they can do it with processes, why can't they do it with threads?
It's more a case of "THREADS DON'T WORK THAT WAY!" rather than "can't be done".
A thread's supposed to be lightweight; a simple means of achieving
multiprocessing. If you follow the reliability angle through and add
resource tracking and whatnot you end up with a thread that's basically just
as fat as a process. A thread's not supposed to be isolated from anything;
that's not their purpose.
What you're looking for actually has less to do with threads and more with
isolating components (which may or may not be using separate threads) from
each other's failures. But here "failure" has to be defined so generally as
to make any form of isolation lower than process level well nigh useless.
If in my thread I do something like:
MyList = new List<string>;
And then when I kill the thread, windows says the List was created in the
thread and therefor will be nuked, it is my problem. I could write my app in
such a way that I know where stuff was allocated so that I could expect
MyList to go away. The CLR could go as far as making any references to
MyList null or just throwing an exception of I try and use it (besides
assigning it a new value).
But what's the point?
If you are in a position to terminate the thread properly, you're also in a
position to know what resources should be thrown away. So why don't you do
that, instead of demanding that the CLR save your bacon at a considerable
(and in 99% of the cases, unnecessary) overhead?
Now, if you're using someone else's component, you don't know what resources
they're squirreling away, so you could say that's an argument in favor of
CLR tracking. But hang on a moment -- how do you know what threads the
misbehaving component is using, and how do you select the one that's
blocking in a way you don't want it to for termination? If you can dig deep
enough to figure that out, can't you also figure out what resources it's
abusing and dispose of them?
Indefinitely blocking threads are such a huge pain in the ass because
recognizing when a thread is never going to do something meaningful again is
in theory equivalent to the halting problem and in practice not actually
that much easier. It's like asking the OS for an infinite loop detector. It
could try, but it'd run into unsolvable cases pretty soon.
Having said all that, I understand the sentiment about writing good code and
how none of this is necessary. Unfortunately, that is a 'if the world were
perfect...' point of view in an imperfect world.
If the world were perfect, the operating system and the runtime would join
hands to ensure that nothing you ever did could cause state corruption, and
every error condition was recoverable. But since that's a theoretical
impossibility, they have to settle somewhere before that. Threads were never
meant to be an aid in this. They're actually more like aggravating factors.
The process is the one edge where they can reasonably isolate the rest of
the system from most of the impact of failure. And even that fails when
processes are cooperating to get something done. Try killing off "csrss.exe"
sometime. If you succeed, it's rebooting time, baby. Your other processes
will be just as doomed.
In this particular case, I need SSH, which for some reason Microsoft doesn't
seem to see fit as being a core protocol for C# (or .NET in general).
Hey, they have to give third-party developers *some* chance at a living,
don't they?
I suggested this on the community sites, and got a 'resolved' and 'won't
fix' with no reasons supplied. The only valid reason I can think of is
because SSH support is in the works, however after much googling I can't
find any hint about official MS SSH support. With their big security
push, and SSH being a cornerstone in network security management, this
makes absolutely no sense.
Windows has no native (read: Microsoft-supplied) SSH services. That's the
most obvious reason I can think of. .NET heavily focuses on making all of
Windows available through the managed API, but it doesn't go out of its way
to support stuff that isn't ubiquitous on Windows already. And SSH isn't
ubiquitous on Windows -- RDP over VPN is much more common. I say this
without offering judgement on how things are or should be.
Maybe they are waiting until the security crowd starts beating them with
a stick and hail it as yet another reason to use Linux. How long would it
take a few of MS well trained developers to put out a great SSH suite for
.NET? Ignoring the bureaucracy, it should only take a few actual weeks
of development time.
It's not a case of "MS has so much resources, they could do this". Because
every developer and his janitor has a feature they clamor for this way ("why
isn't this just in the base classes so I don't have to think about it
anymore?") It's a big win for the developers, but it has to be a win for
Microsoft too. If there's not enough business incentive for Microsoft to
develop, distribute and support it then they won't do it. Simple as that.
It's weird how in the Unix world everyone cheers when a third-party
developer brings out Yet Another implementation of a well-known protocol,
but how in the Windows world the developers are looking over at Microsoft
expectantly to build everything they need and give it to them. It's true
that Microsoft plays a big role in encouraging this attitude, but still.
This leaves me with a choice of writing my own implementation or using some
other library. My employer is not going to want me to spend several weeks
to write my own or fix this SharpSSH library. Personally, I wouldn't mind,
but really, I have a lot to do.
I just googled ".NET SSH". You don't want to know how many hits I got (and
some of them relevant, even!) What made SharpSSH the monopolist? What about
my suggestion of using an ActiveX control? Is it just a case of not wanting
or being able to spend any money? You get what you pay for...
If you're waiting for MS to turn into a charity and do the things your
company doesn't have the time or money for, then don't forget to pick up a
lottery ticket every day, because you're sure to win in the meantime. Say hi
to your competitors for me.
Considering we are living in an imperfect world, we should try to be
accommodating. Yes, the right thing is to NOT screw something up, but it
WILL happen. The proper thing isn't to stand around and talk about how it
should have been done right, and if it was all your problems would go away.
You're absolutely right. The proper thing is not to stand around and talk
about it but to *do* things right. There has to be a point, somewhere, where
you have to stop talking about general stopgaps and have to get down to
where the actual problem is, because stopgaps only go so far. The OS can't
fix problems with hung threads for you. It already allows you to kill them
off Completely Dead through TerminateThread() if you really think you know
what you're doing. (You probably don't, which is why it's so dangerous.)
That is not fixing the problems, though. And releasing all resources we
somehow deem "belonging" to that thread still isn't fixing the problems.
Tacking on a tracking system for releasing resources is just not a
cost-effective tradeoff. For most applications, the problem will *not* be in
releasing the resources, it's in the fact that whatever they're doing is
going completely wrong. Some applications might just be able to continue
without any problem if the particular action the thread was working on fails
spectacularly, but most will not. They're more likely to grind to a halt. If
you're killing off a thread, you'll probably be killing off your process soon.
Microsoft's job on this kind of issue is to make life as a programmer as
easy as possible. I will grant you that compared to OS X and Linux stuff,
Microsoft is a rock-star, but in a more absolute sense there is a lot they
could do much, much better.
I really have to disagree, at least on this particular issue. You're asking
for the impossible. They can give you the Big Red Emergency Button, and it's
already present in the form of .Abort, and if that doesn't work
TerminateThread(). But you want that button to magically keep your
application in serviceable condition as it's killing off an integral part of
it, and that can't be done.
For example, the current issue, Locked up threads. Granted a good program
will never have this problem, but a realistic response outlook would be that
we have to deal with 'bad' things. A better approach would be for MS to
figure out a way to create a thread and provide some kind of emergency
recovery system.
TerminateThread() *will* get rid of the thread. But the only one who can
"recover" is you. And if the component that failed you is a black box to
you, you're just as sunk as the OS would be.
You could make it a special kind of thread used to run unsafe stuff and
the architecture will save you from what is in the thread if worst comes
to worst. It would be like a container for uranium. You have to use
it, and you hope nothing goes wrong, but if it does, it is contained.
Uranium is easy. That's just radiation. Threads can do *anything*. And most
of the time they're *cooperating* with other threads to get things done.
Good luck automagically containing things.
Another way (not to drag this rant any longer) to look at this is to look
back in the days where there was no memory protection for applications.
One rogue application could bring the entire system down. To take today's
outlook on threads and apply it to that, it would be the same thing as
simply saying, "Clearly the solution to rogue applications is to not run
rogue applications." Ignoring the fact that AwsomeApp.exe is the ONLY app
that does what you need.
See above for the whole "the buck stops somewhere" point. If you want this
protection (and it's indeed a good thing the OS has this), then by all
means, isolate the failing component in a process. The OS can guarantee that
it will at least keep your main process safe from wrongdoings as far as
internal state goes (the failing app might still have corrupted your drive
or something annoying like that, but you stand a good chance).
But that's the thing: that's what *processes* are for. Processes only
started working that way when the OS said they did: before that, processes
could exchange memory directly, as ugly and error-prone as that was. Then
the OS said: "No, stop that -- processes are isolated, and if you want to
cooperate, do it explicitly". But threads are not for isolation and they
never were, they're for integration! They're "lightweight processes", where
"lightweight" means "fast because I do the least amount of work possible to
manage them, they're all yours".
Your argument simply doesn't hold water for threads: it's impossible for
thread X to be "the only thread that does what you need". The thread is just
a way to achieve parallel execution! It's not some sort of isolation box for
computations that aren't under your control. What you want is to isolate
*components*, not threads. Unfortunately, most components can't meaningfully
be isolated, since they have to be able to do anything.