2016-09-04 4 views
1

Я читал об этом deadlock condition, что я уверен, что это влияет на мой код (см. Ниже). Я не понимаю: этот код отлично работал на Windows Server 2003 (.net 2.0) в течение последних 12 лет. Теперь мы пытаемся перенести его на Windows Server 2012, где он всегда блокируется.Исключение процесса. Подождите, когда вы закончите()/StandardOutput, состояние взаимоблокировки

Хотя мои DLL-файлы построены для «anyCPU» (по-прежнему нацеливаются на .net 2.0), исполняемый процесс, который выполняется, абсолютно 32-битный, а переход с Server 2003 на Server 2012 происходит от 32-битного до 64- разрядной ОС.

Я думаю, что я понимаю, что делать, чтобы решить проблему, но кто-нибудь знает, почему это поведение изменилось бы с Server 2003 на Server 2012?

public string DoMyProcess(string filenameAndPath, string arguments) 
{ 
    string stdout=""; 
    int exitCode = 0;    

    try 
    {    
     ProcessStartInfo procStartInfo = new ProcessStartInfo(); 
     procStartInfo.FileName = filenameAndPath; 
     procStartInfo.CreateNoWindow = true; 
     procStartInfo.Arguments = arguments;    
     procStartInfo.RedirectStandardOutput = true; 
     procStartInfo.UseShellExecute = false; 

     System.Diagnostics.Process theProcess = null; 
     try 
     { 
      theProcess = Process.Start(procStartInfo); 
      theProcess.WaitForExit(); 

      exitCode = theProcess.ExitCode; 

      // moving this ABOVE WaitForExit should eliminate deadlocks 
      // But why did it always work on Server 2003 but not on Server 2012? 
      stdout = theProcess.StandardOutput.ReadToEnd(); 

     } 
     catch (System.Exception e) 
     { 
      string errMsg = e.Message; 
      log_the_error("threw an exception: " + e.Message); 
     }     
    }   

    return stdout; 
} 

UPDATE:

Mystery тупиковый все еще существует, даже после изменения приведенного выше кода в соответствии с рекомендациями:

 try 
     { 
      theProcess = Process.Start(procStartInfo); 
      stdout = theProcess.StandardOutput.ReadToEnd();      
     } 
     catch (System.Exception e) 
     { 
      string errMsg = e.Message; 
      log_the_error("threw an exception: " + e.Message); 
     }     
    }   

Какие другие условия могут привести к этой тупиковой ситуации? Если бы я изучил StandardError, он бы показал что-нибудь полезное?

UPDATE # 2:

FWIW мы предоставлены другой Windows Server 2003 (32-разрядная версия), которая работает IIS 6. Это была исходная конфигурация машины этого код работал на протяжении 12 лет (с только случайным тупиковая). Наш же код, который накладывает блокировки на Server 2012 IIS 8, НЕ ОТКЛЮЧАЕТСЯ на этом сервере 2003.

Теперь у нас есть свой собственный минимальный и полный код, который воспроизводит проблему. Однако .exe, который мы лицензировали, который выполняется процессом, содержит условия конфиденциальности, которые мешают нам публиковать сообщения. Я понимаю, что здесь не помогают эксперты.

ОДИН СОВЕТ, с которым мы столкнулись, заключается в том, что при запуске через отладчик Visual Studio 2013, установленном на фактическом сервере, процесс не блокируется/зависает, вызывая процесс из браузера ВНЕШНИЙ сервер. И как ни странно - из браузера ON THE SERVER 2012 мы не можем подключиться к этой тестовой странице - браузер просто говорит «подключиться» и, в конечном итоге, отключается (однако другие сайты, размещенные на одном и том же сервере IIS 8, могут быть удалены из браузера на сервере!)

Так как те же параметры командной строки, запускаемые вручную из командной оболочки команд или командной оболочки, отличной от admin, трудно поверить, что это проблема 64-бит/WOW64 с этим 32-разрядный исполняемый файл или требуемые DLL. Мы продолжаем искать места, где наши разрешения могут вызывать проблемы (процесс должен записываться в временную папку, которую мы установили в c: \ temp, пока).

+1

Я знаю, что ошибочный шаблон кода распространен в Интернете, но попробуйте использовать пример MS для [Process.OutputDataReceived Event] (https://msdn.microsoft.com/en-us/library/system.diagnostics .process.outputdatareceived (v = vs.110) .aspx? cs-save-lang = 1 & cs-lang = csharp # code-snippet-2) в качестве отправной точки. Помните, что это событие и другие события процесса поступают на вторичный поток, поэтому планируйте соответственно. – TnTinMn

+0

re: ваше отредактированное обновление, ничего не осталось в коде, который должен вызвать тупик. Это не значит, что нет ... вы не предоставили [mcve], так что невозможно понять, какой другой код может быть здесь работает. Чтение 'StandardError' может показывать или не показывать ничего полезного; вы можете неправильно интерпретировать какую-то ошибку или приглашение пользователя во внешнем процессе как тупик, когда на самом деле он просто ждет вас или что-то еще, чтобы ответить. Обратите внимание, что если вы _do_ перенаправляете 'StandardError', тогда вы вводите возможность тупика и захотите убедиться, что вы это избегаете. –

+1

У меня есть несколько разных ответов SO, которые, отвечая на вопросы, отличные от тех, которые у вас здесь есть, включают примеры перенаправления как «StandardOutput», так и «StandardError» без блокировки кода. Вы можете найти один или несколько из них полезными: http://stackoverflow.com/a/33508142, http://stackoverflow.com/a/26722542 и http://stackoverflow.com/a/38881345 –

ответ

1

Без хорошего Minimal, Complete, and Verifiable code example ответить невозможно.

Что я могу вам сказать, так это то, что ваш код всегда был сломан и всегда был в тупике. Вы не можете прочитать что-либо из процесса до тех пор, пока процесс не завершится, но процесс может не удаться, если он записывает столько данных в stdout, что буфер заполняет и блокирует процесс.

Если вы еще не перекомпилировали что-либо, но обнаружили, что теперь вы видите тупик, когда вы этого не делали раньше, наиболее вероятным объяснением является то, что процесс, который вы начинаете, записывает больше в стандартный вывод, чем раньше. То есть весь выход, используемый для размещения в буфере раньше, но теперь это не так. (Я думаю, также возможно, что размер буфера был уменьшен в более новой ОС, но это кажется мне маловероятным.)

Вы должны позвонить и перезвонить по телефону ReadToEnd(). Фактически, вы должны покончить с WaitForExit() вообще. Если вы звоните ReadToEnd(), это не будет завершено до тех пор, пока процесс фактически не выйдет, так что вызов WaitForExit() впоследствии будет бессмысленным.

+0

Я считаю, что ты прав. Код был частью примера от поставщика, который был достаточно опытным, что они должны были поймать это - наши инженеры были новичками с .net в то время. – SMGreenfield