Click here to Skip to main content
15,886,689 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I use CancellationToken to cancel a task. So I need to register it.
C#
public void Test(T t, CancellationToken cToken)
{
    try
    {
         cToken.Register(() =>
         {
               // stop task and log something
         });
          // normal work.

In the above code, I put cToken.Register before normal work.
My question is that does it matter the position? Can I place it after normal work?
Posted
Comments
Tomas Takac 7-Nov-14 15:12pm    
If you are registering action to cancel normal work then definitely yes.
[no name] 7-Nov-14 15:22pm    
But I had an example, it had different outcome. See here.
Tomas Takac 7-Nov-14 16:45pm    
And did you read the first answer? "... you must register before you start ..."
[no name] 7-Nov-14 16:53pm    
Yeah. That is what I am saying. ... you must register before you start ... means I have to put the register before the normal work. So it matters the position. However I felt that your opinion is different from his, also I got an answer from the other web site. Which is the register's position doesn't matter, so I am confused these different answers.
Tomas Takac 7-Nov-14 17:20pm    
I'm sorry for being unclear. It matters when you register your cancellation action. You are doing some work you want to be able to cancel. So it makes no sense to register the cancellation action after you already finished your work, correct? CancellationToken merely gives you the signal that cancellation was requested, you need to act on it. This logic needs to be in place before you start your work otherwise you will miss the cancellation signal.

1 solution

It matters when you register your cancellation action. You are doing some work you want to be able to cancel. So it makes no sense to register the cancellation action after you already finished your work, correct? CancellationToken merely gives you the signal that cancellation was requested, you need to act on it. This logic needs to be in place before you start your work otherwise you will miss the cancellation signal. Consider following code:

C#
void Main()
{
    // start the worker with cancellation token, wait for 1sec then cancel the work in progress
    var source = new CancellationTokenSource();
    var task = Task.Factory.StartNew(() => DoWork(source.Token));
    Thread.Sleep(1000);
    source.Cancel();
    task.Wait();
}

void DoWork(CancellationToken token)
{
    object locker = new Object(); // simple lock to simulate work

    token.Register(() =>
    {
        // on cancel pulse the lock to wake up the worker
        lock (locker)
        {
            Console.WriteLine("Cancel signal");
            Monitor.Pulse(locker);
        }
    });

    // our work is waiting on the lock, not more than 2sec
    // Wait() returns true if lock was pulsed, false otherwise
    lock (locker)
    {
        var cancelled = Monitor.Wait(locker, 2000);
        Console.WriteLine("Cancelled: " + cancelled);
    }
}


The above example runs about 1sec and prints following output:

Cancel signal
Cancelled: True


If you move the registration after the actual work like this:
C#
void DoWork(CancellationToken token)
{
    object locker = new Object(); // simple lock to simulate work

    // our work is waiting on the lock, not more than 2sec
    // Wait() returns true if lock was pulsed, false otherwise
    lock (locker)
    {
        var cancelled = Monitor.Wait(locker, 2000);
        Console.WriteLine("Cancelled: " + cancelled);
    }

    token.Register(() =>
    {
        // on cancel pulse the lock to wake up the worker
        lock (locker)
        {
            Console.WriteLine("Cancel signal");
            Monitor.Pulse(locker);
        }
    });
}


Then it will run 2sec and print this:
Cancelled: False
Cancel signal


Please note that the cancellation action is invoked even it was registered after the token was signaled. This is consistent with MSDN[^] saying: If this token is already in the canceled state, the delegate will be run immediately.
 
Share this answer
 
Comments
[no name] 8-Nov-14 8:45am    
Tomas, that makes sense. Actually I want to go further. My normal work is playing a sound with a long paragraph. Because it is too long, I may cancel it at any time.

The function:
VoiceResource.PlayTTS("A long paragraph");
To stop it, the function is:
VoiceResource.Stop();
The hard issue is I don't know when the calcellation token is passed. If it is in the middle of playing, then cancel it. Then I have to put the token register before the my normal work(playing). It does work and interrupts it.

However there is a situation: I click the cancel button early, the token is passed. The playing has not started at all. After a little time, the code run into playing part. In this case, the sound keeps playing and not stop. I don't know how to put the register on where.
Tomas Takac 8-Nov-14 9:30am    
I don't understand what this means: "The hard issue is I don't know when the cancellation token is passed".
[no name] 8-Nov-14 9:39am    
Ignore it. Sorry for unclear. I meant that I didn't know whether the playing had started or not. I just clicked the cancel button then run
cToken.Clear();
In this case, what I want to is to stop my normal work anyway. Put the register before the playing can't stop it if the playing has not started even signaling the cancellation.
Tomas Takac 8-Nov-14 9:48am    
Actually it can. Because if the token is already signaled the registered action is executed immediately. You may want to have a flag which says if the playback has already started or not.

void DoWork(CancellationToken token)
{
bool started = false;

token.Register(() =>
{
if(started) ... cancel ...
});

started = true;
... start playback ...
}
[no name] 8-Nov-14 10:15am    
Tomas, it is a multiple tasks application. The question is there is no way to set up a flag when in the middle of "Playing". We don't know whether the work started or not. In the multiple tasks, some playing may start already and others maybe not. What I want is to cancel all. Would you please look at the whole story at stackoverflow

If you think I need to begin a new question and close this one, that is fine. Let me know please.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900