zoukankan      html  css  js  c++  java
  • Tips&Tricks系列五:Process.WaitForExit()与死锁

    前段时间遇到一个问题,搞得焦头烂额,现在记录下来,希望对大家有所帮助。

    程序里我使用Process类启动命令行,执行批处理文件 'Create.cmd'(当我手工将此文件拖入命令行执行时,一切正常)。C#程序代码类似如下,其中batchFilePath变量为批处理文件全路径:

    Code


    批处理文件'Create.cmd'调用'sqlplus'来执行若干个sql文件:
    //===================================================
    echo Tables on level 0:
    if exist InstallScripts\Create01.sql (
     echo bas
     sqlplus %1/%2@%3 @InstallScripts\Create01.sql | %HideSQLPlusRows%
     REM > Logs\Create_%1.txt
    )
    if exist InstallScripts\Create02.sql (
    ......
    //===================================================

    出现的问题是程序运行到'm_BasicDataProc.WaitForExit();'这一行时就阴塞不动.

    搞了两天,最后发现原因是出现了死锁。由于标准输出流被重定向,而Process.StandardOutput的缓冲大小是有限制的(据说是4k),所以当缓冲满了的时候(执行上面的批处理文件有很多的输出),子进程(cmd.exe)会等待主进程(C# App)读取并释放此缓冲,而主进程由于调用了WaitForExit()方法,则会一进等待子进程退出,最后形成死锁。

    了解了原因后,有3种方法可以解决问题:
    1)修改批处理文件,在调用sqlplus时将输出指定到一个log文件,这样被生定向到StandardOutput中的内容相对就少,不容易造成问题:
    //===================================================
    echo Tables on level 0:
    if exist InstallScripts\Create01.sql (
     echo bas
     sqlplus %1/%2@%3 @InstallScripts\Create01.sql | %HideSQLPlusRows% > Logs\Create_%1.txt
    )
    ......
    //===================================================

    2)修改C#代码,将'm_BasicDataProc.StartInfo.RedirectStandardOutput = false;',这样所有的输出会在命令行屏幕上直接输出,不会重定向到标准输出流中。

    3)修改C#代码,在'm_BasicDataProc.WaitForExit();'前添加'm_BasicDataProc.BeginOutputReadLine();' 或 'm_BasicDataProc.StandardOutput.ReadToEnd();',通过读取输出流,以便释放相应的缓冲。

  • 相关阅读:
    257. Binary Tree Paths
    324. Wiggle Sort II
    315. Count of Smaller Numbers After Self
    350. Intersection of Two Arrays II
    295. Find Median from Data Stream
    289. Game of Life
    287. Find the Duplicate Number
    279. Perfect Squares
    384. Shuffle an Array
    E
  • 原文地址:https://www.cnblogs.com/morvenhuang/p/1561629.html
Copyright © 2011-2022 走看看