首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么StreamWriter.AutoFlush要把这个打印两次?

为什么StreamWriter.AutoFlush要把这个打印两次?
EN

Stack Overflow用户
提问于 2016-01-28 22:46:12
回答 1查看 573关注 0票数 0

为什么以下只在StreamWriter.AutoFlush设置为true时才打印重复消息?

代码语言:javascript
复制
using (var stream = log.Open(FileMode.Append, FileAccess.Write, FileShare.Read))
{
    using (var streamWriter = new StreamWriter(stream))
    {
        /****************************/
        streamWriter.AutoFlush = true;
        /****************************/
        streamWriter.WriteLine(new string('-', 80));
        streamWriter.WriteLine(file.FullName);
        streamWriter.WriteLine(new string('-', 80));
        try
        {
            await Runner.Run(
                file, // Argument passed in. In this case, points to ConsoleApplication10.exe
                streamWriter,
                streamWriter);
        }
        catch (Exception ex)
        {
            streamWriter.WriteLine(ex.ToString());
            throw;
        }
    }
}

下面是.AutoFlush=true被注释掉时的文件内容:

代码语言:javascript
复制
--------------------------------------------------------------------------------
(path removed for security)\ConsoleApplication10.exe
--------------------------------------------------------------------------------
Out: 1/28/2016 5:19:22 PM
Err: 1/28/2016 5:19:22 PM

以下是.AutoFlush=true时的文件内容。注意重复的行:

代码语言:javascript
复制
--------------------------------------------------------------------------------
(path removed for security)\ConsoleApplication10.exe
--------------------------------------------------------------------------------
Out: 1/28/2016 5:11:59 PM
Out: 1/28/2016 5:11:59 PM
Err: 1/28/2016 5:11:59 PM

ConsoleApplication10.exe的源代码中没有任何意外:

代码语言:javascript
复制
static void Main(string[] args)
{
    Console.Out.WriteLine("Out: " + DateTime.Now.ToString());
    Console.Error.WriteLine("Err: " + DateTime.Now.ToString());
}

这是Runner.Run。请注意,它以与当前用户不同的凭据集启动进程。除此之外,它只是管道、stderr和stdout,类似于https://msdn.microsoft.com/en-us/library/system.diagnostics.process.outputdatareceived(v=vs.110).aspx中给出的示例

代码语言:javascript
复制
public static async Task Run(FileInfo executable, TextWriter writerForStandardOutput, TextWriter writerForStandardError)
{
    if (!executable.Exists)
        throw new Exception("The given executable doesn't exist");

    // Start the process
    using (var process = new Process())
    {
        // Set up the process's start info
        process.StartInfo = new ProcessStartInfo()
        {
            CreateNoWindow = true,
            Domain = DOMAIN, // The domain needs to be specified or you'll get an error that says "The stub received bad data"
            FileName = executable.FullName,
            LoadUserProfile = true, // Set to true so that functionality isn't unnecessarily limited for the credentials this program will run under
            Password = PASSWORD,
            RedirectStandardError = true, // We'll be capturing errors
            RedirectStandardOutput = true, // We'll be capturing output
            UserName = USERNAME,
            UseShellExecute = false, // Can't specify credentials to use unless this is set to false
            WindowStyle = ProcessWindowStyle.Hidden
        };

        // Set up listeners for when output or error data is received
        process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
        {
            if (!ReferenceEquals(e.Data, null))
                writerForStandardOutput.WriteLine(e.Data);
        });
        process.ErrorDataReceived += new DataReceivedEventHandler((sender, e) =>
        {
            if (!ReferenceEquals(e.Data, null))
                writerForStandardError.WriteLine(e.Data);
        });

        // Try to start the executable
        process.Start();
        // Begin redirecting stdout and stderr
        process.BeginOutputReadLine();
        process.BeginErrorReadLine();

        // Wait for the process to end
        await Task.Run(() => { process.WaitForExit(); });
    }
}

我正在使用.Net 4.6。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-01-28 23:16:11

@usr对这个问题的评论是正确的。根本原因是以非线程安全的方式写入streamWriter。将Runner.Run更改为此可以修复它。注意lock语句的存在使写入同步:

代码语言:javascript
复制
public static async Task Run(FileInfo executable, TextWriter writerForStandardOutput, TextWriter writerForStandardError)
{
    if (!executable.Exists)
        throw new Exception("The given executable doesn't exist");

    // Start the process
    using (var process = new Process())
    {
        // Set up the process's start info
        process.StartInfo = new ProcessStartInfo()
        {
            CreateNoWindow = true,
            Domain = DOMAIN, // The domain needs to be specified or you'll get an error that says "The stub received bad data"
            FileName = executable.FullName,
            LoadUserProfile = true, // Set to true so that functionality isn't unnecessarily limited for the credentials this program will run under
            Password = PASSWORD,
            RedirectStandardError = true, // We'll be capturing errors
            RedirectStandardOutput = true, // We'll be capturing output
            UserName = USERNAME,
            UseShellExecute = false, // Can't specify credentials to use unless this is set to false
            WindowStyle = ProcessWindowStyle.Hidden
        };

        // Create an object for synchronizing writes to the output and error TextWriter objects
        var lockObject = new object();

        // Set up listeners for when output or error data is received
        process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
        {
            if (!ReferenceEquals(e.Data, null))
            {
                lock (lockObject)
                {
                    writerForStandardOutput.WriteLine(e.Data);
                }
            }
        });
        process.ErrorDataReceived += new DataReceivedEventHandler((sender, e) =>
        {
            if (!ReferenceEquals(e.Data, null))
            {
                lock (lockObject)
                {
                    writerForStandardError.WriteLine(e.Data);
                }
            }
        });

        // Try to start the executable
        process.Start();
        // Begin redirecting stdout and stderr
        process.BeginOutputReadLine();
        process.BeginErrorReadLine();

        // Wait for the process to end
        await Task.Run(() => { process.WaitForExit(); });
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35073617

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档