2012-06-09 15 views
5

Tôi có một số mã sinh ra một số pthread cố gắng duy trì kết nối ổ cắm với máy chủ từ xa. Nếu kết nối bị mất, nó sẽ cố gắng kết nối lại bằng cách sử dụng lệnh chặn connect() trên ổ cắm của nó. Vì mã chạy trong một luồng riêng biệt, tôi không thực sự quan tâm đến việc nó sử dụng API socket đồng bộ.Làm thế nào để ngắt một luồng thực hiện một ổ cắm chặn kết nối?

Tức là, cho đến khi ứng dụng của tôi xuất hiện. Tôi muốn thực hiện một số semblance của một shutdown trật tự, vì vậy tôi sử dụng nguyên gốc đồng bộ hóa thread để đánh thức các chủ đề và tín hiệu cho nó để thoát, sau đó thực hiện một pthread_join() trên thread để chờ đợi cho nó để hoàn thành. Điều này làm việc tuyệt vời, trừ khi thread đang ở giữa một cuộc gọi connect() khi tôi lệnh tắt máy. Trong trường hợp đó, tôi phải chờ kết nối hết thời gian, có thể là một thời gian dài. Điều này làm cho ứng dụng xuất hiện mất nhiều thời gian để tắt.

Điều tôi muốn làm là làm gián đoạn cuộc gọi đến connect() theo một cách nào đó. Sau khi cuộc gọi trả về, luồng sẽ nhận thấy tín hiệu thoát của tôi và tắt hoàn toàn. Vì connect() là một cuộc gọi hệ thống, tôi nghĩ rằng tôi có thể cố ý làm gián đoạn nó bằng tín hiệu (do đó thực hiện cuộc gọi trở lại EINTR), nhưng tôi không chắc đây có phải là phương pháp mạnh mẽ trong môi trường chủ đề POSIX hay không.

Có ai có bất kỳ đề xuất nào về cách thực hiện việc này, sử dụng tín hiệu hoặc thông qua một số phương pháp khác không? Lưu ý rằng cuộc gọi connect() bị gỡ xuống trong một số mã thư viện mà tôi không thể sửa đổi, do đó việc thay đổi sang ổ cắm không chặn không phải là một tùy chọn.

+2

Cũng vui lòng đặt thẻ ngôn ngữ. – Tudor

+0

Tôi thực sự viết bằng Python, nhưng tôi không tìm kiếm bất kỳ ngôn ngữ cụ thể nào. Bạn có thể giả định rằng tôi đang hoạt động trên Linux. –

+1

Đóng ổ cắm. –

Trả lời

6

Cố gắng đóng() ổ cắm để ngắt kết nối kết nối(). Tôi không chắc chắn, nhưng tôi nghĩ nó sẽ hoạt động ít nhất trên Linux. Tất nhiên, hãy cẩn thận để đồng bộ hóa đúng cách mà bạn chỉ bao giờ đóng() ổ cắm này một lần hoặc đóng() về mặt lý thuyết có thể đóng mô tả tệp không liên quan vừa được mở.

EDIT: tắt máy() có thể phù hợp hơn vì nó không thực sự đóng socket. Bạn cũng có thể xem pthread_cancel()pthread_kill(). Tuy nhiên, tôi không thấy cách nào để sử dụng hai điều này mà không có tình trạng chạy đua.

Tôi khuyên bạn nên từ bỏ phương pháp tiếp cận đa luồng-máy chủ và thay vào đó đi theo hướng sự kiện, ví dụ bằng cách sử dụng epoll để thông báo sự kiện. Bằng cách này bạn có thể tránh tất cả những vấn đề rất cơ bản này trở nên rất khó khăn với các chủ đề, như tắt máy đúng cách. Bạn được tự do làm bất cứ lúc nào bạn muốn, ví dụ: một cách an toàn đóng ổ cắm và không bao giờ nghe từ họ một lần nữa.

Mặt khác, nếu trong chủ đề công nhân của bạn, bạn làm một non-blocking connect() và nhận được thông báo qua epoll_pwait() (hoặc ppoll() hoặc pselect(); lưu ý p), bạn có thể tránh điều kiện cuộc đua liên quan đến tín hiệu.

+0

Cảm ơn gợi ý sử dụng 'close()'; Tôi sẽ xem xét điều đó. Tôi đồng ý rằng một cơ chế hướng sự kiện sẽ tốt hơn.Tuy nhiên, như tôi đã lưu ý trong câu hỏi của tôi, "cuộc gọi' connect() 'nằm trong một số mã thư viện mà tôi không thể sửa đổi, do đó việc thay đổi sang một ổ cắm không chặn không phải là một lựa chọn." –

+0

Phần "không thể sửa đổi" phải là một vấn đề lớn ở đây. Như tôi đã lưu ý, hãy cẩn thận về việc không đóng hai lần; thư viện có thể muốn đóng() sau khi connect() trả về. Bạn đã cân nhắc việc chấm dứt quy trình bằng vũ lực khi bạn hoàn thành tất cả nội dung của mình, đảm bảo mã xâm lấn không hoạt động sai cho đến thời điểm đó? –

+2

Tôi đã đi với đề xuất của bạn để sử dụng 'shutdown()'. Vì thư viện được viết bằng Python, tôi có thể nhìn trộm và truy cập vào socket bên dưới và sau đó tắt nó. Nó hoạt động tốt. Không phải là cách tiếp cận tốt nhất từ ​​góc độ kiến ​​trúc phần mềm, nhưng nó hoạt động ở đây và tôi có quyền kiểm soát phiên bản của thư viện sẽ được sử dụng. –