3

I have a program in C# which does some services calls. I need to add some code in this program in order to be able to stop these services calls if I click on a button (winform) [For example, if the call is too long and the user is bored].

The difficulty is that I can't modify the blocks of code which do the calls.

In order to do so, I've planned to do some Interception with the Unity Framework. I would like to create a Task each time I enter a service-call block of code. Then, cancel this task if the user clicks on my Button.

I've looked about CancellationToken but the problem is that I can't modify the calls-blocks, so I can't do if(ct.IsCancellationRequested) or ct.ThrowIfCancellationRequested(); Same thing for the AutoResetEvent & ManualResetEvent. The calls are not always asynchronous and made with a cancellationToken, so catching OperationCanceledExceptionis, I think, impossible.

I've also looked about using Threads and do some Thread.Abort() but this method seems to kill puppies each time someone calls it.

Here is a sample of my current program (the Interception is not implemented yet, I want to test it on a single call first) :

private void Test()
{
    Task.Factory.StartNew(MyServiceCallFunction); // How to cancel the task when I press a button ?
}

// Can't touch the inside of this function :
private void MyServiceCallFunction()
{
    // Blabla I prepare the datas for the call
    // Blabla I do the call
}

How can I do that ? (I'm not obliged to use a task)

Thank you,

loxidur
  • 47
  • 1
  • 3
  • This is why I prefer threads though the community usually explodes about it. If you use a thread instead of a task, you can just call `Thread.Abort()` and catch the `ThreadAbortException`. – user1274820 Nov 22 '16 at 20:02
  • 2
    Don't use `Thread`s, unless you think you can manage them better than .NET framework – hyankov Nov 22 '16 at 20:04
  • Think he can manage a single thread? No, apparently that's impossible for anyone -_-; – user1274820 Nov 22 '16 at 20:05
  • 2
    @user1274820 The fact that you just don't care about all of the problems that you're causing doesn't mean that they don't exist. The TPL doesn't expose a means of aborting the underlying threads not because it's trying to be cruel, or as an oversight, but because users simply aren't aware of the complications that it causes and how to design their program in such a way that it will function in the face of arbitrary exceptions being thrown virtually anywhere in the code. Almost no programs on the planet function properly in that situation. – Servy Nov 22 '16 at 20:07
  • I find it humorous because I have built countless applications that have functioned for years without issue that regularly abort threads (sometimes using multiple threads). I have never had a single issue using `Thread.Abort()`. I would LOVE to see an example of it "messing something up" when it is used in simple context such as this. – user1274820 Nov 22 '16 at 20:08
  • @loxidur, does the `MyServiceCallFunction()` call something outside? A service or another function? Maybe you can interrupt it there. – hyankov Nov 22 '16 at 20:09
  • @user1274820 Were you even looking? Would you even know if the operations didn't work, or if they did some, but not all of their work, if they didn't clean up their resources properly, if they failed to properly log an issue because of the non-cooperative shutdown, etc.? Again, that you haven't noticed a problem doesn't mean they aren't there. They're often that much more insidious because you *don't* see them. – Servy Nov 22 '16 at 20:12
  • 2
    Possible duplicate of [Is it possible to abort a Task like aborting a Thread (Thread.Abort method)?](http://stackoverflow.com/questions/4359910/is-it-possible-to-abort-a-task-like-aborting-a-thread-thread-abort-method) – Wagner DosAnjos Nov 22 '16 at 20:12
  • A "problem" that causes no discernible issues ever is inherently NOT a problem. – user1274820 Nov 22 '16 at 20:12
  • 1
    @user1274820 So if you're standing in the road and a car is barreling at you you cover your eyes, because a problem that you don't notice isn't a problem? That you don't realize bad things are happening doesn't mean they aren't happening, it just means you're that much less capable of actually addressing those problems. – Servy Nov 22 '16 at 20:14
  • A car driving toward me is not a "bad" thing. A car hitting me is a bad thing. If the car never hits me, I don't care how often it drives towards me. – user1274820 Nov 22 '16 at 20:14
  • @HristoYankov is right, don't use `Thread.Abort()`! Ever! This long deprecated and can have serious side effects. – Wagner DosAnjos Nov 22 '16 at 20:14
  • 2
    @wdosanjos Please stop spreading misinformation. `Thread.Abort()` is not depreciated. Look it up. – user1274820 Nov 22 '16 at 20:15
  • 1
    When was Thread.Abort() deprecated? https://msdn.microsoft.com/en-us/library/5b50fdsz(v=vs.110).aspx – Peter Mourfield Nov 22 '16 at 20:16
  • @user1274820 So that's a yes, you're the type of person that ignores anything that's virtually certainly going to be a problem, and refuses to take any measures to prevent any problem from ever occurring, and only ever consider acting after a problem (including a *literally fatal* problem) has already happened? You do realize that after you've had a fatal problem it is already *too late* to concern yourself with it? – Servy Nov 22 '16 at 20:19
  • @Servy I don't understand what part of this you don't understand. My software never had an issue with thread aborts - it ran for years and years and years. It is the equivalent of screaming at me "watch out for the dangerous cars!" when I am watching them go by from afar. There was never a "crash", there was never an accident, nobody ever died in this metaphor - so yes, your concerns are unfounded. – user1274820 Nov 22 '16 at 20:23
  • @user1274820 That's the morale equivalent of saying, "I cross major highways all the time without ever looking if there's traffic coming, and I've never been hit. You should totally feel free to just jump out into any road at any time, and you'll never get hit." Sure, if you live in northern Saskatchewan you may well be able to do that for years and years and never have a problem, but if you give that advice to someone in New York City they're going to end up dead by the end of the day. And even you could end up dead, even though the odds are lower in the middle of nowhere. – Servy Nov 22 '16 at 20:29
  • @Servy No, it's the equivalent of saying - cars are dangerous, but if you're careful, you can safely cross the street. What you're arguing is that you can never cross the street safely which is untrue. `Thread.Abort()` exists for a reason, and it works in cases such as this where you are forced to kill a thread during a long task that you have no control over. Yes, it is not ideal, but these cases sometimes come up and we have a tool to handle them. – user1274820 Nov 22 '16 at 20:29
  • @user1274820 You saying that indicates that you don't actually understand what `Thread.Abort` actually does, or how it interacts with just about any actual real life C# program. You don't just call it whenever you feel like it for any program ever written under any circumstances because there's almost no chance that it will ever not work perfectly. It's effectively only ever safe to use by code that was specifically designed and written to function properly when being aborted (which almost no one ever writes). – Servy Nov 22 '16 at 20:32
  • 1
    I only know fake life C# programs apparently. Show me an example of `Thread.Abort()` doing anything wrong/breaking things? This is the only situation I have seen documented where it says `Thread.Abort()` may not actually abort the thread (that's the "danger"). `The thread is not guaranteed to abort immediately, or at all. This situation can occur if a thread does an unbounded amount of computation in the finally blocks that are called as part of the abort procedure, thereby indefinitely delaying the abort.` Last time I checked, complex code in finally blocks is bad programming practice too. – user1274820 Nov 22 '16 at 20:37
  • 1
    @user1274820 The program could have temp files created and not cleaned up, or leave such state in a corrupted state, causing problems in subsequent executions, it could have made some changes to the registry, but not finished, leaving it in an invalid state, it could end up leaking unmanaged resources, if it's performing network activity (like, say, this question is specifically asking about) then aborting the thread in no way actually stops the network request that has been sent out, so aborting the thread doesn't actually abort the logical operation it represents, etc. – Servy Nov 22 '16 at 20:41
  • 1
    Basically, about the only thing that you can actually reliably abort is an operation that computes an in-memory value, never interacts with any system outside of that thread's memory (including other threads). You also need to ensure that any synchronization mechanism uses by this process are specifically designed to work in the face of it being aborted, else you can rather easily deadlock the program. – Servy Nov 22 '16 at 20:44
  • @Servy Which of those things is his program doing? You don't know? Don't you think someone wanting to abort a task has considered what it is they're aborting? Or do you imagine that everyone is retarded and has no clue what they're doing? – user1274820 Nov 22 '16 at 20:46
  • @user1274820 We *know* given the question, that the operation is a network request. Thus, we know that aborting it doesn't actually stop the request, it just stops the thread from waiting for the response (the same thing that you could accomplish with a `CancellationToken` without aborting the thread would accomplish). Meanwhile you're the one saying that you're entirely confident that there is no chance at all that there will ever be any problems, rather than specifically mentining the (rather narrow) contexts in which it is actually appropriate. – Servy Nov 22 '16 at 20:49
  • It's possible/typical that the response is requesting data and that cancelling it (ignoring the response) has no ill effects at all whatsoever - yet you insist that it is always wrong like so many others. Every actually written socket code? It's nearly impossible to "cleanly" close a connection - you're always throwing away exceptions. I just can't stand the answer "it's impossible" when there is a simple solution. – user1274820 Nov 22 '16 at 20:52
  • 1
    I guess we should read [Eric Lippert's comments on `Thread.Abort()`](http://stackoverflow.com/a/1560567/106159). I quote from that: `Thread.Abort is at best indicative of bad design, possibly unreliable, and extremely dangerous. It should be avoided at all costs` (but hey - what does he know? He only worked on developing the C# language...) – Matthew Watson Nov 22 '16 at 21:08
  • @user1274820 But your "simple solution" doesn't actually solve the problem. You haven't actually cancelled the operation that you claim to have canceled. In that one example, even if you do it in such a way that it doesn't cause any additional problems for the rest of the program (not a trivial task) you're still facing the fact that *you didn't actually cancel anything*. That you'd rather implement a solution that doesn't work, and lie to yourself saying it worked, rather than admit that you didn't actually solve the problem isn't productive. – Servy Nov 22 '16 at 21:19
  • 1
    Lots of negativity here and that's unfortunate. Anyone else have an "acceptable" answer to this question? If so, please post it. – Peter Mourfield Nov 22 '16 at 21:22
  • To both Servy and Matthew - I agree that `Thread.Abort()` should be avoided. I'm not trying to spread negativity - merely point out that `Thread.Abort()` does work and is required in some cases (unfortunate as that may be). Rather than claim it is "impossible" to do such a simple task, I, and others, have offered a solution that works. To dissuade from `Thread.Abort()` use in other instances is acceptable, but when it is a valid option (perhaps, given your silence, the only option?) - why do you continue to dissuade its use? Please see this thread: http://stackoverflow.com/a/21715122/1274820 – user1274820 Nov 22 '16 at 21:25
  • 1
    These are all conversations that have already happened - you say `Thread.Abort()` is bad, but offer no alternative. We offer a solution. Who is being helpful here? – user1274820 Nov 22 '16 at 21:25
  • OP, please choose one... i'm sick of this. you have your options. – Igor Quirino Nov 22 '16 at 21:36

2 Answers2

2

The "correct" way to do it is to used CancellationTokens but since you can't modify the running code the only other way is to kill the puppies and use Thread.Abort()

Something like:

Thread t;
Task.Factory.StartNew(() =>
    {
        t = Thread.CurrentThread;
        MyServiceCallFunction();
    });

t.Abort();
Peter Mourfield
  • 1,885
  • 1
  • 19
  • 38
  • 1
    ^ This - for better or for worse - is simple and works 99.99% of the time. – user1274820 Nov 22 '16 at 20:11
  • @user1274820 It's not *always* wrong, it's just often wrong, and suggesting its usage in situations where it's not appropriate, and without appropriate indications of when those situations are, just because it looks easy, despite all of the problems and headaches it's likely going to cause to someone looking for an effective solution, is more harmful than helpful. That you feel so proud of helping people cause problems is...depressing. – Servy Nov 22 '16 at 20:17
  • 1
    @Servy the fact that you accept "it's impossible" as a response to a question when there is code that makes it possible is depressing to me. – user1274820 Nov 22 '16 at 20:18
  • @user1274820 That you're saying that indicates that you don't understand what the code actually does. That you think that it solves the problem *when it doesn't actually solve the problem* makes you worse off then having realized that the problem was not in fact solved. Also, I didn't say that solving the problem was impossible, just that this approach isn't an acceptable solution. – Servy Nov 22 '16 at 20:21
  • This is just an aberration. The thread used by a task is managed by the TaskScheduler, that's the point of tasks, let .net manage threads. You're aborting it, you don't know which side effects can have this. – Gusman Nov 22 '16 at 20:31
  • 2
    @oxidur take it or leave it for what it is. As I said originally, the correct way is to use cancellation tokens but since you say you can't, see if this works for you. Fair warning: test thoroughly and use at your own risk. As you said, this solution is akin to killing puppies but may work in your situation. – Peter Mourfield Nov 22 '16 at 20:53
-1

Very Interesting question. Of course you cannot do anything when the third party call is doing TPL; in your case it is MyServiceCallFunction().

I have been in the similar situation where this blog post has helped me: https://social.msdn.microsoft.com/Forums/vstudio/en-US/d0bcb415-fb1e-42e4-90f8-c43a088537fb/aborting-a-long-running-task-in-tpl?forum=parallelextensions

(read: Stephen Toub - MSFTMicrosoft (MSFT) comments)

He has mentioned this solution:

int Test(CancellationToken token)
    {
        Thread currentThread = Thread.CurrentThread;
        using (token.Register(currentThread.Abort))
        {
            MyServiceCallFunction()
        }
    }

Also replace Task.Factory.StartNew (...) with Task.Run(...) ; same, infect latter is stronger, but better readable.

codebased
  • 6,945
  • 9
  • 50
  • 84
  • Also using `Thread.Abort()`, but linking it with the `CancellationToken` so that it seems "more right." I wonder how the community will accept this response. – user1274820 Nov 22 '16 at 20:16