Cách tốt nhất trên nền tảng Linux cho quy trình (ứng dụng C++) để kiểm tra cá thể của nó là gì chưa chạy?Ngăn chặn nhiều cá thể quá trình trên Linux
Trả lời
Cách tiêu chuẩn để thực hiện việc này là tạo một tệp pidfile ở đâu đó, thường chứa pid của chương trình của bạn.
Bạn không cần phải đặt pid vào đó, bạn chỉ có thể đặt một khóa độc quyền trên đó. Nếu bạn mở nó để đọc/ghi và đổ nó bằng LOCK_EX | LOCK_NB, nó sẽ thất bại nếu tập tin đã bị khóa. Đây là điều kiện chủng tộc miễn phí và khóa sẽ tự động được phát hành nếu chương trình gặp sự cố.
Thông thường bạn muốn làm điều đó cho mỗi người dùng, vì vậy thư mục chính của người dùng là nơi tốt để đặt tệp.
Nếu đó là một daemon, ở đâu đó giống như/var/run thì tốt hơn.
Bạn có thể sử dụng tệp và khóa tệp để thực hiện việc này, nhưng hãy cẩn thận nó không hoàn hảo và không sao chép lỗi Firefox khét tiếng mà từ chối đôi khi bắt đầu ngay cả khi nó chưa chạy.
Logic cơ bản của nó là:
Invariant:
File xxxxx will exist if and only if the program is running, and the
contents of the file will contain the PID of that program.
On startup:
If file xxxxx exists:
If there is a process with the PID contained in the file:
Assume there is some instance of the program, and exit
Else:
Assume that the program terminated abnormally, and
overwrite file xxxx with the PID of this program
Else:
Create file xxxx, and save the current PID to that file.
On termination (typically registered via atexit):
Delete file xxxxx
Ngoài logic trên, bạn cũng nên sử dụng một tập tin thứ hai mà bạn khóa để đồng bộ hóa quyền truy cập vào các tập tin PID (tức là hoạt động như một mutex để làm cho nó an toàn về mặt đồng thời).
Một giải pháp thay thế liên quan đến giải pháp của Michael là tạo thư mục ở vị trí đã biết (có thể dưới/var/run hoặc/tmp) và sử dụng thành công/thất bại của cuộc gọi hệ thống làm cơ chế đảm bảo loại trừ lẫn nhau. Đây là cùng một mẹo loại trừ lẫn nhau mà CVS đã sử dụng trong nhiều năm khi tạo thư mục là nguyên tử trên hầu hết các hệ điều hành hàng hóa (có thể là tất cả). Tệp PID vẫn hữu ích trong trường hợp quá trình tạo thư mục + PID chết đột ngột và không dọn dẹp được. Ngoài ra, khi kiểm tra xem thư mục hiện có + PID có hợp lệ không, tôi khuyên bạn nên kiểm tra rõ ràng liên kết tượng trưng /proc/<PID>/exe
để xác minh rằng nó trỏ đến tệp thực thi của bạn thay vì giả định PID không được tái chế.
Bạn có thể sử dụng POSIX named semaphore để thực hiện việc này. Nó an toàn hơn nhiều so với việc sử dụng khóa tập tin.
Làm thế nào để đối phó với một chương trình bị hỏng mà không làm sạch lên semaphore? –
từ trang người đàn ông: POSIX có tên là semaphores có hạt nhân kiên trì: nếu không bị xóa bởi sem_unlink(), một semaphore sẽ tồn tại cho đến khi hệ thống bị tắt. Crash chắc chắn sẽ là một vấn đề ở đây. – jackhab
Đối với ứng dụng dành cho máy tính để bàn, có thể kiểm tra xem một cá thể có được bắt đầu cho người dùng hiện tại, để hai người dùng có thể chạy phiên bản riêng của họ hay không.
Bạn có thể sử dụng một trong hai thư viện (libunique (GTK +) hoặc QtSingleApplication (Qt)) hoặc tự làm. Ngoài tệp pid được đề cập trước đó, bạn có thể mở ổ cắm FIFO hoặc miền UNIX ở đâu đó trong thư mục chính của người dùng. Bằng cách này, bạn có thể giao tiếp với cá thể đang chạy, ví dụ. nâng cao cửa sổ của cá thể đang chạy hoặc yêu cầu chạy thể hiện để mở tệp mới/URI/bất kỳ thứ gì.
Việc sử dụng ổ cắm thay vì một tệp và cố gắng liên kết với một cổng được xác định trước có đơn giản hơn không? Và, bằng cách này, tại sao tôi không thể sử dụng khóa tập tin mà không có tất cả các xác minh pid? – jackhab
@Jack, bạn có thể làm điều đó mà không cần xác minh PID, nhưng sau đó bạn chạy các nguy cơ giả định chương trình được mở khi nó đã thực sự bị rơi và không dọn dẹp các tập tin (nghĩ rằng vấn đề Firefox). Ngoài ra, Rakis đưa ra một điểm tốt, đó là, trên Linux, bạn có thể xác minh rằng PID thuộc về chương trình của bạn bằng cách sử dụng dữ liệu trong '/ proc' ... có những cách lập trình để làm điều đó một cách tổng quát hơn trên các biến thể UNIX (ít nhất bạn có thể gọi "ps" và phân tích đầu ra của nó, mặc dù tôi tin rằng có thể có các hàm bạn có thể gọi để thu thập thông tin quy trình trực tiếp). –
để kiểm tra sự tồn tại của một quá trình, gọi kill (pid, 0). Điều này thành công khi quá trình tồn tại, không thành công. Hãy coi chừng quá trình chạy trên một máy khác! – Arkadiy