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

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

m_BasicDataProc = new Process();
m_BasicDataProc.StartInfo.FileName = "cmd.exe";
m_BasicDataProc.StartInfo.CreateNoWindow = false;
m_BasicDataProc.StartInfo.UseShellExecute = false;
m_BasicDataProc.StartInfo.RedirectStandardOutput = true;
m_BasicDataProc.StartInfo.RedirectStandardInput = true;
m_BasicDataProc.StartInfo.WorkingDirectory = Path.GetDirectoryName(batchFilePath);
m_BasicDataProc.Start();
string batchFileName = Path.GetFileName(batchFilePath);
StreamWriter inputStream = m_BasicDataProc.StandardInput;
inputStream.WriteLine(batchFileName);
inputStream.Close();
m_BasicDataProc.WaitForExit();
m_BasicDataProc.EnableRaisingEvents = true;

批处理文件'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();',通过读取输出流,以便释放相应的缓冲。

C# Process.WaitForExit()与死锁的更多相关文章

  1. 使用Process类重定向输出与错误时遇到的问题 (转)

    程序中要调用外部程序cmd.exe执行一些命令行,并取得屏幕输出,使用了Process类,基本代码如下: Process process = new Process(); process.StartI ...

  2. Process启动.exe,当.exe内部抛出异常时,总会弹出一个错误提示框,阻止Process进入结束

    public class TaskProcess { [DllImport("kernel32.dll", SetLastError = true)] public static ...

  3. C# process 使用方法

    public static string ExecuteAaptCommand(string appName, string command) { string result = string.Emp ...

  4. C#启动进程之Process

    在程序设计中,我们经常会遇到要从当前的程序跳到另一个程序的设计需求.也就是当前进程创建另一个进程.C#提供了Process使得我们很方便的实现. 1.Process基本属性和方法 Id //进程的Id ...

  5. Process Class (System.Diagnostics)

    import sys def hanoi(n, a, b, c): if n == 1: print('%c --> %c' % (a, c)) else: hanoi(n-1, a, c, b ...

  6. Process.start: how to get the output?

    1: Synchronous example static void runCommand() { Process process = new Process(); process.StartInfo ...

  7. Process使用

    最近在一个项目中,需要在C#中调用cmd窗口来执行一个命令,使用到了Process这个类,使用过程中遇到不少问题,好在终于解决了.赶紧记录下来. Process process = new Proce ...

  8. Process类的使用

    Process process= new Process(); process.StartInfo.CreateNoWindow = true; process.StartInfo.UseShellE ...

  9. 关于.Net中Process的使用方法和各种用途汇总(二):用Process启动cmd.exe完成将cs编译成dll

    上一章博客我为大家介绍了Process类的所有基本使用方法,这一章博客我来为大家做一个小扩展,来熟悉一下Process类的实际使用,废话不多说我们开始演示. 先看看我们的软件要设计成的布局吧. 首先我 ...

随机推荐

  1. Apache 去掉 www

    1 用phpstudy的网友打开“其他选项菜单”- “配置文件”-httpd-conf.找到 #LoadModule rewrite_module modules/mod_rewrite.so 把这一 ...

  2. mysql 命令连接

    远程登陆MySQL,同时指定对应的端口和ip. 假设远程的ip为:10.154.0.43 端口为:1341 输入如下命令: mysql -h 10.154.0.43 -P 1341 -u root - ...

  3. 求一个区间里的一个x,这个x与这区间里面的所有数都互质

    链接:https://ac.nowcoder.com/acm/contest/301/H来源:牛客网 题描述 小乐乐上了一节数学课,数学老师讲的很好,小乐乐听的也如痴如醉. 小乐乐听了老师的讲解,知道 ...

  4. 115th LeetCode Weekly Contest Check Completeness of a Binary Tree

    Given a binary tree, determine if it is a complete binary tree. Definition of a complete binary tree ...

  5. layer.open中content里面的元素追加click事件,触发不了

    [注意] 事件要追加在触发弹出事件的点击事件里面 $('#feedback').click(function(){ layer.open({ content:'<div><div c ...

  6. jquery 属性选择器

    jquery 属性选择器   第一种根据属性选择E[attr] $("[title]").click().......... 即选择所有元素内 属性带有title的元素即<l ...

  7. xampp安装步骤及启动

    1  chmod 755 xampp-linux-*-installer.run 2 sudo ./xampp-linux-*-installer.run 启动停止 3 sudo /opt/lampp ...

  8. 设置Log文件每天生成一个(wamp)

    打开 Wamp的 httpd.conf文件 把下面两句话拷贝进去即可: 1.设置错误log的,    " 2.设置访问log的    " common    说明:bin/rota ...

  9. [Activator- HelloAkka] Define our Messages

    An Actor does not have a public API in terms of methods that you can invoke. Instead its public API ...

  10. js中防止事件传播的方法

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...