Làm thế nào tôi có thể biết nếu một quá trình đang chạy?


155

Khi tôi nhận được một tham chiếu đến a System.Diagnostics.Process, làm thế nào tôi có thể biết nếu một quy trình hiện đang chạy?

Câu trả lời:


252

Đây là một cách để làm điều đó với tên:

Process[] pname = Process.GetProcessesByName("notepad");
if (pname.Length == 0)
  MessageBox.Show("nothing");
else
  MessageBox.Show("run");

Bạn có thể lặp tất cả quá trình để lấy ID cho thao tác sau:

Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
   Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}

Điều này thật đúng với gì mà tôi đã tìm kiếm. Mặc dù đây là một bài viết rất cũ, nhưng bạn sẽ giải thích cho tôi làm thế nào đây là C # hợp lệ. Tôi không nghi ngờ gì, tôi thấy nó hoạt động, nhưng tôi chưa bao giờ thấy nếu không có {}.
MatthewD

4
@MatthewD: Các if/elsecâu lệnh C # chỉ dài một dòng không cần phải có dấu ngoặc nhọn để biểu thị câu lệnh khối. Điều này cũng đi foreachfortuyên bố. Nó sôi sục theo phong cách mã hóa.
Hallmanac

Tôi cũng đã làm một số nghiên cứu về điều này, tìm thấy thông tin đó, nhưng tôi không thấy forthông tin đó. Nhiều năm c # .net dev và tôi chưa bao giờ thấy phong cách này. Giống như họ nói, "bạn học được điều gì đó mới mỗi ngày". Cảm ơn bạn đã gửi bài và trả lời ..
MatthewD

3
@MatthewD yeah, điều này đúng với hầu hết các ngôn ngữ (như Java). Nói chung, nên tránh sử dụng một lớp lót như thế này và luôn đặt niềng răng, vì luôn có cơ hội bạn có thể phải thêm nhiều câu lệnh trong tương lai, trong trường hợp đó, niềng răng sẽ ở đó khi bạn cần. Nhưng đối với những việc như thế này, nếu bạn chắc chắn 100% bạn chỉ cần một tuyên bố, bạn có thể làm được và có hiệu lực về mặt cú pháp.
David Mordigal

1
Nếu bạn không thể tìm thấy quy trình, hãy thử xóa tiện ích mở rộng. (Ví dụ: .exe)
DxTx

28

Đây là cách đơn giản nhất mà tôi tìm thấy sau khi sử dụng gương phản xạ. Tôi đã tạo một phương thức mở rộng cho điều đó:

public static class ProcessExtensions
{
    public static bool IsRunning(this Process process)
    {
        if (process == null) 
            throw new ArgumentNullException("process");

        try
        {
            Process.GetProcessById(process.Id);
        }
        catch (ArgumentException)
        {
            return false;
        }
        return true;
    }
}

Các Process.GetProcessById(processId)phương pháp gọi là ProcessManager.IsProcessRunning(processId)phương pháp và ném ArgumentExceptiontrong trường hợp quá trình này không tồn tại. Vì một số lý do, ProcessManagerlớp học là nội bộ ...


Đây là một câu trả lời thực sự tốt; tuy nhiên, bạn không nên có ngoại lệ null đối số (Vì dù sao ngoại lệ tham chiếu null cũng sẽ bị ném và bạn không làm gì với ngoại lệ. Ngoài ra, bạn sẽ nhận được một UnlimitedOperationException nếu bạn không gọi Start () phương thức hoặc bạn đã gọi phương thức close (). Tôi đã đăng một Câu trả lời khác để giải thích cho hai tình huống này.
Aelphaeis

16

Giải pháp đồng bộ:

void DisplayProcessStatus(Process process)
{
    process.Refresh();  // Important


    if(process.HasExited)
    {
        Console.WriteLine("Exited.");
    }
    else
    {
        Console.WriteLine("Running.");
    } 
}

Giải pháp không đồng bộ:

void RegisterProcessExit(Process process)
{
    // NOTE there will be a race condition with the caller here
    //   how to fix it is left as an exercise
    process.Exited += process_Exited;
}

static void process_Exited(object sender, EventArgs e)
{
   Console.WriteLine("Process has exited.");
}

6
Đối với tùy chọn đầu tiên: làm thế nào tôi có thể biết liệu quy trình đã được bắt đầu ở nơi đầu tiên chưa?
hình lại

8

reshefm đã có một câu trả lời khá hay; tuy nhiên, nó không giải thích cho một tình huống trong đó quá trình không bao giờ bắt đầu.

Đây là một phiên bản sửa đổi của những gì ông đã đăng.

    public static bool IsRunning(this Process process)
    {
        try  {Process.GetProcessById(process.Id);}
        catch (InvalidOperationException) { return false; }
        catch (ArgumentException){return false;}
        return true;
    }

Tôi đã xóa ArgumentNullException của anh ấy vì nó thực sự là một ngoại lệ tham chiếu null và dù sao nó cũng bị hệ thống ném và tôi cũng tính đến tình huống trong đó quy trình không bao giờ bắt đầu bằng hoặc phương thức close () được sử dụng để đóng quá trình.


Cá nhân, tôi rất muốn thấy một ArgumentNullException khi xem xét một ngoại lệ được ghi lại hơn là NullReferenceException, vì ArgumentNullException rõ ràng hơn về những gì đã sai.
Sean

1
@Sean tôi thường đồng ý với bạn nhưng đây là một phương thức mở rộng. Tôi nghĩ rằng sẽ phù hợp hơn khi ném một ngoại lệ con trỏ null theo cú pháp, nó chỉ cảm thấy phù hợp hơn với các phương thức gọi của các đối tượng null.
Aelphaeis

Điều này sẽ kích hoạt trình xử lý sự kiện FirstHandledException mỗi lần. Cách để spam nhật ký của bạn đấy bạn ạ.
Độ trễ

6

Đây phải là một lớp lót:

public static class ProcessHelpers {
    public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}

3

Nó phụ thuộc vào mức độ tin cậy của bạn muốn chức năng này. Nếu bạn muốn biết nếu ví dụ quy trình cụ thể mà bạn có vẫn đang chạy và có sẵn với độ chính xác 100% thì bạn đã hết may mắn. Lý do là từ đối tượng quy trình được quản lý chỉ có 2 cách để xác định quy trình.

Đầu tiên là Id quá trình. Thật không may, id quá trình không phải là duy nhất và có thể được tái chế. Tìm kiếm danh sách quy trình cho Id phù hợp sẽ chỉ cho bạn biết rằng có một quy trình có cùng id đang chạy, nhưng đó không nhất thiết là quy trình của bạn.

Mục thứ hai là Xử lý quy trình. Nó có cùng một vấn đề với Id và thật khó xử lý hơn.

Nếu bạn đang tìm kiếm độ tin cậy ở mức trung bình thì việc kiểm tra danh sách quy trình hiện tại cho một quy trình có cùng ID là đủ.


1

Process.GetProcesses()là con đường để đi Nhưng bạn có thể cần sử dụng một hoặc nhiều tiêu chí khác nhau để tìm quy trình của mình, tùy thuộc vào cách nó đang chạy (ví dụ như một dịch vụ hoặc ứng dụng thông thường, cho dù nó có thanh tiêu đề hay không).


Nếu bạn đặt phương thức này trong một vòng lặp, nó sẽ tốn rất nhiều chu kỳ CPU. Tôi khuyên bạn nên sử dụng GetProcessByName () hoặc GetProcessByID ().
Hao Nguyen

0

Có thể (có lẽ) Tôi đang đọc câu hỏi sai, nhưng bạn đang tìm thuộc tính HasExited sẽ cho bạn biết rằng quy trình được đại diện bởi đối tượng Process của bạn đã thoát (bình thường hoặc không).

Nếu quy trình bạn có tham chiếu để có UI, bạn có thể sử dụng thuộc tính Phản hồi để xác định xem UI hiện có phản hồi với đầu vào của người dùng hay không.

Bạn cũng có thể đặt EnableRaisingEvents và xử lý sự kiện Đã thoát (được gửi không đồng bộ) hoặc gọi WaitForExit () nếu bạn muốn chặn.


0

Bạn có thể khởi tạo một cá thể Process một lần cho quy trình bạn muốn và tiếp tục theo dõi quá trình bằng cách sử dụng đối tượng .NET Process đó (nó sẽ tiếp tục theo dõi cho đến khi bạn gọi Close trên đối tượng .NET đó, ngay cả khi quá trình mà nó đang theo dõi đã chết [điều này là để có thể cung cấp cho bạn thời gian xử lý gần, còn gọi là ExitTime, v.v.))

Trích dẫn http://msdn.microsoft.com/en-us/l Library / fb4aw7b8.aspx :

Khi một quy trình liên quan thoát ra (nghĩa là khi hệ thống vận hành ngừng hoạt động thông qua chấm dứt bình thường hoặc bất thường), hệ thống sẽ lưu trữ thông tin quản trị về quy trình và trở về thành phần có tên WaitForExit. Thành phần Process sau đó có thể truy cập thông tin, bao gồm ExitTime, bằng cách sử dụng Xử lý cho quy trình đã thoát.

Vì quy trình liên quan đã thoát, thuộc tính Xử lý của thành phần không còn trỏ đến tài nguyên quy trình hiện có. Thay vào đó, tay cầm chỉ có thể được sử dụng để truy cập thông tin của hệ điều hành về tài nguyên quy trình. Hệ thống nhận thức được việc xử lý các tiến trình đã thoát mà các thành phần Process chưa phát hành, do đó, nó giữ thông tin ExitTime và Xử lý trong bộ nhớ cho đến khi thành phần Process giải phóng cụ thể các tài nguyên. Vì lý do này, bất cứ khi nào bạn gọi Bắt đầu cho một cá thể Quy trình, hãy gọi Đóng khi quá trình liên quan đã chấm dứt và bạn không còn cần bất kỳ thông tin quản trị nào về nó. Đóng giải phóng bộ nhớ được phân bổ cho quá trình thoát.


0

Tôi đã thử giải pháp của Coincoin:
Trước khi xử lý một số tệp, tôi sao chép nó dưới dạng tệp tạm thời và mở tệp.
Khi tôi hoàn tất, tôi đóng ứng dụng nếu nó vẫn mở và xóa tệp tạm thời:
Tôi chỉ sử dụng biến Quy trình và kiểm tra sau đó:

private Process openApplication;  
private void btnOpenFile_Click(object sender, EventArgs e) {  
    ...
    // copy current file to fileCache  
    ...  
    // open fileCache with proper application
    openApplication = System.Diagnostics.Process.Start( fileCache );  
}

Sau đó tôi đóng ứng dụng:

 ...   
openApplication.Refresh(); 

// close application if it is still open       
if ( !openApplication.HasExited() ) {
    openApplication.Kill();  
}

// delete temporary file  
System.IO.File.Delete( fileCache );

Nó hoạt động (cho đến nay)


3
Tại openApplication.HasExited(), HasExited không phải là một chức năng. Cách chính xác sẽ là openApplication.HasExited.
caiosm1005

0

Mặc dù API được hỗ trợ từ các khung .Net liên quan đến việc kiểm tra quy trình hiện tại bằng ID tiến trình, các chức năng đó rất chậm. Nó tốn một số lượng lớn chu kỳ CPU để chạy Process.GetProcesses () hoặc Process.GetProcessById / Name ().

Một phương pháp nhanh hơn nhiều để kiểm tra một quy trình đang chạy bằng ID là sử dụng API OpenProcess () gốc . Nếu xử lý trả về là 0, quá trình không tồn tại. Nếu xử lý khác 0, quá trình đang chạy. Không có gì đảm bảo phương pháp này sẽ hoạt động 100% mọi lúc do sự cho phép.


0

Có nhiều vấn đề liên quan đến vấn đề này, vì những vấn đề khác dường như đã giải quyết một phần:

  • Bất kỳ thành viên thể hiện không được đảm bảo là chủ đề an toàn. Có nghĩa là có các điều kiện chủng tộc có thể xảy ra với thời gian chụp nhanh trong khi cố gắng đánh giá các thuộc tính của đối tượng.
  • Việc xử lý quy trình sẽ đưa Win32Exception cho ACCESS DENIED nơi các quyền để đánh giá điều này và các thuộc tính khác không được phép.
  • Đối với trạng thái RUNNING của ISN, một ArgumentException cũng sẽ được nêu ra khi cố gắng đánh giá một số thuộc tính của nó.

Cho dù các thuộc tính mà người khác đã đề cập có phải là nội bộ hay không, bạn vẫn có thể lấy thông tin từ chúng thông qua phản ánh nếu được phép.

var x = obj.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);

Bạn có thể xác định mã Win32 cho Ảnh chụp nhanh hoặc bạn có thể sử dụng WMI chậm hơn.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

Một tùy chọn khác sẽ là OpenProcess / CloseProcess, nhưng bạn vẫn sẽ gặp phải các vấn đề tương tự với các ngoại lệ được đưa ra như trước đây.

Đối với WMI - OnNewEvent.ProperIES ["?"]:

  • "ParentProcessID"
  • "Xử lý ID"
  • "Tên xử lý"
  • "SECURITY_DESCRIPTOR"
  • "Phiên họp"
  • "Sid"
  • "TIME_CREATED"

0
string process = "notepad";
if (Process.GetProcessesByName(process).Length == 0)
{
    MessageBox.Show("Working");
}
else
{
    MessageBox.Show("Not Working");
}

ngoài ra bạn có thể sử dụng một bộ đếm thời gian để kiểm tra quá trình mỗi lần


3
Sẽ không phải là cách khác? nếu chiều dài == 0 có nghĩa là không hoạt động?
Jay Jacobs

Câu trả lời giống như của Patrick Desjardins: stackoverflow.com/a/262291/7713750
Rekshino

Cách khác của nó xung quanh chiều dài> 0 có nghĩa là các quá trình được tìm thấy.
HaseeB Mir

Điều này có thể có lỗi, ( length == 0nên hiển thị Not Working) nhưng vẫn hoàn thành công việc.
Momoro
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.