C # - Tạo Quy trình. Bắt đầu đợi cho đến khi quy trình khởi động


77

Tôi cần đảm bảo rằng một quy trình đang chạy trước khi tiếp tục với một phương thức.

Tuyên bố là:

Process.Start("popup.exe");

Bạn có thể thực hiện lệnh WAIT hoặc đặt độ trễ cho giá trị này không?


"Đảm bảo" nghĩa là gì? Phải có một thứ cụ thể bạn cần chạy trong popup.exe, phải không? Nếu vậy, chờ đợi nó chạy sẽ không đủ.
Ed Bayiates

Ngoài ra, bạn có quyền kiểm soát popup.exe không? Có nghĩa là bạn có thể thêm mã vào nó để báo hiệu quá trình sinh sản rằng nó đang chạy không?
Ed Bayiates

Câu trả lời:


137

Ý bạn là đợi cho đến khi nó hoàn thành? Sau đó sử dụng Process.WaitForExit:

var process = new Process {
    StartInfo = new ProcessStartInfo {
        FileName = "popup.exe"
    }
};
process.Start();
process.WaitForExit();

Ngoài ra, nếu đó là một ứng dụng có giao diện người dùng mà bạn đang đợi để nhập vào vòng lặp thông báo, bạn có thể nói:

process.Start();
process.WaitForInputIdle();

Cuối cùng, nếu cả hai đều không áp dụng, chỉ Thread.Sleeptrong một khoảng thời gian hợp lý:

process.Start();
Thread.Sleep(1000); // sleep for one second

1
Trong đoạn mã đầu tiên của bạn, bạn sẽ phải gọi thủ công process.Start()trước đó process.WaitForExit(); nếu không một ngoại lệ sẽ được ném ra.
Bala R

9
Chỉ cần chắc chắn rằng bạn hiểu những gì thực sự làm WaitForInputIdle blogs.msdn.com/b/oldnewthing/archive/2010/03/25/9984720.aspx
ta.speot.is

1
@ ta.speot.is Nói cách khác ... Chính xác thì OP muốn gì?
Cơ bản từ

@Basic Đây là một trang web tham khảo và câu trả lời này có thể được đọc bởi những người không phải là OP.
Eagle-Eye

@ Eagle-Eye Tôi không chắc mình hiểu quan điểm của bạn? ta.speoit.is (không phải OP cho Q hoặc A) ngụ ý rằng tính năng này không hoạt động như quảng cáo. Tôi đã kiểm tra tài liệu và có vẻ như nó thực hiện chính xác những gì OP yêu cầu. Theo cách nào đó đã làm cho trang web trở nên ít hữu ích hơn cho những khách truy cập trong tương lai?
Cơ bản

18

Tôi cũng cần điều này một lần và tôi đã kiểm tra tiêu đề cửa sổ của quá trình. Nếu đó là ứng dụng bạn mong đợi, bạn có thể chắc chắn rằng ứng dụng đang chạy. Ứng dụng tôi đang kiểm tra cần một thời gian để khởi động và phương pháp này hoạt động tốt đối với tôi.

var process = Process.Start("popup.exe");
while(process.MainWindowTitle != "Title")
{
    Thread.Sleep(10);
}

15

Câu trả lời của 'ChrisG' là đúng, nhưng chúng tôi cần phải làm mới MainWindowTitle mỗi lần và tốt hơn là kiểm tra xem có trống không .... như thế này:

var proc = Process.Start("popup.exe");
while (string.IsNullOrEmpty(proc.MainWindowTitle))
{
    System.Threading.Thread.Sleep(100);
    proc.Refresh();
}

2
Chúng ta có thể giả sử một khi một ứng dụng dòng lệnh có tiêu đề thì nó đã được khởi động không?
Jack

1
Tôi đã thêm một câu lệnh kiểm tra bổ sung trong khi:! Proc.HasExited
Vangi

9

Trước hết: Tôi biết điều này khá cũ nhưng vẫn chưa có câu trả lời được chấp nhận, vì vậy có lẽ cách tiếp cận của tôi sẽ giúp ích cho người khác. :)

Những gì tôi đã làm để giải quyết vấn đề này là:

process.Start();

while (true)
{
    try
    {
        var time = process.StartTime;
        break;
    }
    catch (Exception) {}
}

Hiệp hội var time = process.StartTimesẽ ném ra một ngoại lệ miễn là quá trình không bắt đầu. Vì vậy, một khi nó trôi qua, có thể an toàn khi cho rằng tiến trình đang chạy và tiếp tục làm việc với nó. Tôi đang sử dụng cái này để đợi quá trình java khởi động, vì nó mất một khoảng thời gian. Bằng cách này, nó sẽ độc lập trên máy mà ứng dụng đang chạy hơn là sử dụng Thread.Sleep().

Tôi hiểu đây không phải là giải pháp sạch cho lắm, nhưng là giải pháp duy nhất độc lập về hiệu suất mà tôi có thể nghĩ ra.


1
Tuy nhiên, đây là cách đơn giản nhất để có được thông tin cần thiết.
Arturo Torres Sánchez

7

Giống như những người khác đã nói, nó không rõ ràng ngay lập tức những gì bạn đang hỏi. Tôi sẽ giả định rằng bạn muốn bắt đầu một quy trình và sau đó thực hiện một hành động khác khi quy trình "sẵn sàng".

Tất nhiên, "đã sẵn sàng" là một chút khó khăn. Tùy thuộc vào nhu cầu của bạn, bạn có thể thấy rằng chỉ cần chờ đợi là đủ. Tuy nhiên, nếu bạn cần một giải pháp mạnh mẽ hơn, bạn có thể cân nhắc sử dụng Mutex có tên để kiểm soát luồng điều khiển giữa hai quy trình của mình.

Ví dụ: trong quy trình chính của bạn, bạn có thể tạo mutex có tên và bắt đầu một chuỗi hoặc tác vụ sẽ chờ. Sau đó, bạn có thể bắt đầu quá trình thứ hai. Khi quá trình đó quyết định rằng "nó đã sẵn sàng", nó có thể mở mutex được đặt tên (tất nhiên bạn phải sử dụng cùng tên) và báo hiệu cho quá trình đầu tiên.


Đó chính xác là những gì tôi đã mong đợi để tìm thấy khi tôi tìm kiếm điều này. Cảm ơn.
Nicholas Miller

4

Tôi đồng ý với Tom. Ngoài ra, để kiểm tra các tiến trình trong khi thực hiện Thread.Sleep, hãy kiểm tra các tiến trình đang chạy. Cái gì đó như:

bool found = 0;
while (!found)
{
    foreach (Process clsProcess in Process.GetProcesses())
        if (clsProcess.Name == Name)
            found = true;

    Thread.CurrentThread.Sleep(1000);
}

2
while (!Process.GetProcesses().Any(p=>p.Name == myName)) { Thread.Sleep(100); }
dss539

Tại sao không GetProcessesByName()? while(Process.GetProcessesByName(myName).Length == 0) { Thread.Sleep(100); }Trong khi nó có thể làm việc hầu hết phần thời gian, cách thích hợp sẽ chờ đợi cho đến khi n mileseconds và thoát ra khỏi vòng lặp nếu quá trình này đã không được tìm thấy.
Jack

2

Bạn có chắc chắn Startphương thức trả về trước khi tiến trình con bắt đầu không? Tôi luôn có ấn tượng rằng Startbắt đầu quá trình trẻ em một cách đồng bộ.

Nếu bạn muốn đợi cho đến khi quy trình con của bạn hoàn thành một số loại khởi tạo thì bạn cần giao tiếp giữa các quy trình - hãy xem Giao tiếp liên quy trình dành cho Windows trong C # (.NET 2.0) .


1

Để mở rộng ý tưởng của @ ChrisG, hãy xem xét sử dụng process.MainWindowHandle và xem vòng lặp thông báo cửa sổ có phản hồi hay không. Sử dụng p / gọi api Win32 này: SendMessageTimeout . Từ liên kết đó:

Nếu chức năng thành công, giá trị trả về là khác không. SendMessageTimeout không cung cấp thông tin về việc hết thời gian chờ của từng cửa sổ nếu HWND_BROADCAST được sử dụng.

Nếu chức năng bị lỗi hoặc hết thời gian, giá trị trả về là 0. Để nhận thông tin lỗi mở rộng, hãy gọi GetLastError. Nếu GetLastError trả về ERROR_TIMEOUT, thì hàm đã hết thời gian chờ.


1

Tôi đã sử dụng lớp EventWaitHandle . Trên tiến trình mẹ, hãy tạo EventWaitHandle có tên với trạng thái ban đầu của sự kiện được đặt thành không báo hiệu. Tiến trình mẹ sẽ chặn cho đến khi tiến trình con gọi phương thức Set , thay đổi trạng thái của sự kiện thành signaled, như hình dưới đây.

Quy trình dành cho cha mẹ:

using System;
using System.Threading;
using System.Diagnostics;

namespace MyParentProcess
{
    class Program
    {
        static void Main(string[] args)
        {
            EventWaitHandle ewh = null;
            try
            {
                ewh = new EventWaitHandle(false, EventResetMode.AutoReset, "CHILD_PROCESS_READY");

                Process process = Process.Start("MyChildProcess.exe", Process.GetCurrentProcess().Id.ToString());
                if (process != null)
                {
                    if (ewh.WaitOne(10000))
                    {
                        // Child process is ready.
                    }
                }
            }
            catch(Exception exception)
            { }
            finally
            {
                if (ewh != null)
                    ewh.Close();
            }
        }
    }
}

Tiến trình con:

using System;
using System.Threading;
using System.Diagnostics;

namespace MyChildProcess
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                // Representing some time consuming work.
                Thread.Sleep(5000);

                EventWaitHandle.OpenExisting("CHILD_PROCESS_READY")
                    .Set();

                Process.GetProcessById(Convert.ToInt32(args[0]))
                    .WaitForExit();
            }
            catch (Exception exception)
            { }
        }
    }
}

3
Giải pháp tốt nhất ở đây nhưng bạn cần có thể thêm một số mã trong quy trình con.
ViRuSTriNiTy

0

Đây là một triển khai sử dụng a System.Threading.Timer. Có thể hơi nhiều cho mục đích của nó.

    private static bool StartProcess(string filePath, string processName)
    {
        if (!File.Exists(filePath))
            throw new InvalidOperationException($"Unknown filepath: {(string.IsNullOrEmpty(filePath) ? "EMPTY PATH" : filePath)}");

        var isRunning = false;

        using (var resetEvent = new ManualResetEvent(false))
        {

            void Callback(object state)
            {
                if (!IsProcessActive(processName)) return;
                isRunning = true;
                // ReSharper disable once AccessToDisposedClosure
                resetEvent.Set();
            }

            using (new Timer(Callback, null, 0, TimeSpan.FromSeconds(0.5).Milliseconds))
            {
                Process.Start(filePath);
                WaitHandle.WaitAny(new WaitHandle[] { resetEvent }, TimeSpan.FromSeconds(9));
            }
        }

        return isRunning;
    }

    private static bool StopProcess(string processName)
    {
        if (!IsProcessActive(processName)) return true;

        var isRunning = true;

        using (var resetEvent = new ManualResetEvent(false))
        {

            void Callback(object state)
            {
                if (IsProcessActive(processName)) return;
                isRunning = false;
                // ReSharper disable once AccessToDisposedClosure
                resetEvent.Set();
            }

            using (new Timer(Callback, null, 0, TimeSpan.FromSeconds(0.5).Milliseconds))
            {
                foreach (var process in Process.GetProcessesByName(processName))
                    process.Kill();
                WaitHandle.WaitAny(new WaitHandle[] { resetEvent }, TimeSpan.FromSeconds(9));
            }
        }

        return isRunning;
    }

    private static bool IsProcessActive(string processName)
    {
        return Process.GetProcessesByName(processName).Any();
    }

0
public static class WinApi
{

    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    public static class Windows
    {
        public const int NORMAL = 1;
        public const int HIDE = 0;
        public const int RESTORE = 9;
        public const int SHOW = 5;
        public const int MAXIMIXED = 3;
    }

}

Ứng dụng

String process_name = "notepad"
Process process;
process = Process.Start( process_name );

while (!WinApi.ShowWindow(process.MainWindowHandle, WinApi.Windows.NORMAL))
{
    Thread.Sleep(100);
    process.Refresh();
}

// Done!
// Continue your code here ...

0

Bạn cũng có thể kiểm tra xem quá trình đã bắt đầu có đáp ứng hay không bằng cách thử một cái gì đó như sau: while (process.resp Tương ứng)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.