最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - Can race conditions occur between OutputDataReceived and ErrorDataReceived? - Stack Overflow

programmeradmin0浏览0评论

Given the following code and assuming process.OutputDataReceived and process.ErrorDataReceived are accessing the same resource, can race conditions occur?

var process = new Process();
process.OutputDataReceived += ...
process.ErrorDataReceived += ...

Given the following code and assuming process.OutputDataReceived and process.ErrorDataReceived are accessing the same resource, can race conditions occur?

var process = new Process();
process.OutputDataReceived += ...
process.ErrorDataReceived += ...
Share Improve this question asked Jan 19 at 20:06 me.at.codingme.at.coding 17.9k48 gold badges180 silver badges342 bronze badges 6
  • The short answer is YES, The longer answer depends on the implementation of OutputDataReceived and ErrorDataReceived – Luuk Commented Jan 19 at 20:11
  • 1 What do you mean by "accessing the same resource" in this context? – Progman Commented Jan 19 at 20:11
  • The thread in which an event is processed depends is the thread in which the event raised. This is not under your control, so yes, race conditions can occur. – Thomas Weller Commented Jan 19 at 20:15
  • You may consider reading the MS official documentation for StandardError and StandardOutput which discusses this. – It all makes cents Commented Jan 19 at 20:36
  • 1 It is quite unlikely, but technically possible. Which does make it utterly undebuggable when it happens. Luckily it is really simple for your to avoid this trouble, lock makes it trivial. – Hans Passant Commented Jan 19 at 22:43
 |  Show 1 more comment

1 Answer 1

Reset to default 3

It depends on several factors including the process you are running - it can write simultaneously to stdout and stderr. It is easy to check:

Writer:

var iterations = 2000;
var stdout = Task.Run(() =>
{
    for (var i = 0; i < iterations; i++)
    {
        Console.Out.WriteLine(i);
    }
});
var stderr = Task.Run(() =>
{
    for (var i = 0; i < iterations; i++)
    {
        Console.Error.WriteLine(i);
    }
});

await Task.WhenAll(stdout, stderr);

Capturer:

var process = new Process();
int c = 0;
int @out = 0;
int err = 0;
process.StartInfo = new ProcessStartInfo
{
    UseShellExecute = false,
    FileName = "dotnet",
    Arguments = $"{PathToWriterReleaseFolder}/Writer.dll",
    CreateNoWindow = true,
    RedirectStandardError = true,
    RedirectStandardOutput = true
};
process.OutputDataReceived += (sender, args) =>
{
    if (!string.IsNullOrEmpty(args.Data))
    {
        c++;
        @out++;
    }
};
process.ErrorDataReceived += (sender, args) =>
{
    if (!string.IsNullOrEmpty(args.Data))
    {
        c++;
        err++;
    }
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();

Console.WriteLine(c);
Console.WriteLine(@out);
Console.WriteLine(err);

Which gives something like (on my machine - Ubuntu):

3983
2000
2000

Which clearly shows race condition (first number may vary between runs).

Also check the docs for Process.OutputDataReceived/ErrorDataReceived and Process.BeginOutputReadLine/BeginErrorReadLine which explicitly state that this handling is asyncronious:

The event is enabled during asynchronous read operations on StandardOutput. To start asynchronous read operations, you must redirect the StandardOutput stream of a Process, add your event handler to the OutputDataReceived event, and call BeginOutputReadLine. Thereafter, the OutputDataReceived event signals each time the process writes a line to the redirected StandardOutput stream, until the process exits or calls CancelOutputRead.

And

The event only occurs during asynchronous read operations on StandardError. To start asynchronous read operations, you must redirect the StandardError stream of a Process, add your event handler to the ErrorDataReceived event, and call BeginErrorReadLine. Thereafter, the ErrorDataReceived event signals each time the process writes a line to the redirected StandardError stream, until the process exits or calls CancelErrorRead.

发布评论

评论列表(0)

  1. 暂无评论