简体   繁体   中英

Why is Interlocked.Exchange triggering warning CS4014?

The following reduced example generates this compiler warning:

warning CS4014: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

public class TaskInterlockedExchangeTest
{
    private Task _Task;

    public async Task DoSomething()
    {
        Interlocked.Exchange(ref _Task, null);
        await _Task;
    }
}

The warning is raised on the line with the Interlocked.Exchange call. As far as I'm aware Interlocked.Exchange is not async so why on earth is the compiler triggering this warning? Right now this doesn't make any sense to me, so what am I missing?

We do treat warnings as errors so I'm trying to figure out how to fix this (short of disabling the warning around the offending code which I would only see as last resort).

This happens on VS2013 (update 5).

Update

I just discovered that the following avoids the warning:

public class TaskInterlockedExchangeTest
{
    private Task _Task;

    public async Task DoSomething()
    {
        var t = Interlocked.Exchange(ref _Task, null);
        await _Task;
    }
}

So simply assigning the result to a local variable is sufficient.

You're calling the generic overload of Interlocked.Exchange :

public static T Exchange<T>(ref T location1, T value)
    where T : class

Which means the result of the call is a Task . The warning works as designed. It sees you're calling a function which returns a Task , so is potentially asynchronous, but you don't await its result.

The line:

Interlocked.Exchange(ref _Task, null);

Means the following:

  • Replace whatever was in _Task with null
  • Throw out the previous value (given to you as the return value of Interlocked.Exchange )

The following line:

await _Task;

most probably is the equivalent of:

await null;

And will go boom .

I say most probably , since there's a tiny possibility another thread wrote something into _Task , and you're going to await that.

I guess the real code you wanted to write is the following:

public async Task DoSomething()
{
    var task = Interlocked.Exchange(ref _Task, null);

    if (task != null)
        await task;
}

Or, with .NET 4.6:

public async Task DoSomething()
    => await (Interlocked.Exchange(ref _Task, null) ?? Task.CompletedTask);

You may even get rid of the async :

public Task DoSomething()
    => Interlocked.Exchange(ref _Task, null) ?? Task.CompletedTask;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM