2009-03-18 30 views
10

Điều gì xảy ra nếu tôi có một ổ cắm, s, hiện không có dữ liệu trên đó, nó là một ổ cắm chặn và tôi gọi recv trên nó từ hai luồng tại Một lần? Một trong các chủ đề có nhận được dữ liệu không? Cả hai sẽ nhận được nó? Cuộc gọi thứ 2 có bị trả lại là recv không?Gọi recv() trên cùng một ổ cắm chặn từ hai luồng

Trả lời

10

Một chủ đề sẽ nhận được nó và không có cách nào để cho biết.

Điều này dường như không phải là thiết kế hợp lý. Có một lý do tại sao bạn cần hai chủ đề gọi recv() trên cùng một ổ cắm?

+0

không, tôi đang tự mình triển khai dự án và tôi muốn biết điều gì sẽ xảy ra – Claudiu

+0

Tôi đã hỏi vì tôi không thể thấy lý do chính xác để thiết kế theo cách đó. Một trong những lợi ích của luồng là cô lập những thứ như ổ cắm để đơn giản hóa việc xử lý. Chia sẻ lần đọc trên một ổ cắm giữa các chủ đề giới thiệu rất nhiều phức tạp để thay thế. – dwc

+8

Đọc từ cùng một ổ cắm từ hai luồng có ý nghĩa nếu đó là ổ cắm UDP cho giao thức không kết nối như DNS. Mỗi luồng sau đó độc lập hoạt động trên các yêu cầu gửi đến. – bdonlan

3

Triển khai ổ cắm phải an toàn theo luồng, vì vậy, chính xác một luồng sẽ lấy dữ liệu khi có sẵn. Cuộc gọi khác chỉ nên chặn.

3

tôi không thể tìm thấy một tài liệu tham khảo cho việc này, nhưng đây là sự hiểu biết của tôi:

bảo đảm của một nhà cung cấp của thread-an toàn thể có nghĩa là duy nhất mà nhiều chủ đề từng có thể sử dụng một cách an toàn riêng socket của họ; nó không đảm bảo nguyên tử qua một cuộc gọi duy nhất và không hứa hẹn phân bổ cụ thể dữ liệu của socket giữa nhiều luồng.

Giả sử chuỗi Một cuộc gọi recv() trên một ổ cắm đang nhận dữ liệu TCP phát trực tiếp ở tốc độ cao. Nếu recv() cần phải là một cuộc gọi nguyên tử, thì luồng A có thể chặn tất cả các luồng khác thực thi, vì nó cần phải chạy liên tục để kéo tất cả dữ liệu (cho đến khi bộ đệm của nó đầy, anyway.) tốt. Do đó, tôi sẽ không cho rằng recv() là miễn dịch với chuyển đổi ngữ cảnh.

Ngược lại, giả sử luồng A tạo ra một yêu cầu chặn gọi tới recv() trên ổ cắm TCP và dữ liệu đến chậm. Do đó cuộc gọi đến recv() trả về với errno được đặt thành EAGAIN.

Trong cả hai trường hợp này, giả sử chuỗi B gọi recv() trên cùng một socket trong khi luồng A vẫn đang nhận dữ liệu. Khi nào thread A ngừng nhận dữ liệu được truyền cho nó để luồng B có thể bắt đầu nhận dữ liệu? Tôi không biết về một triển khai Unix sẽ cố gắng nhớ rằng luồng A ở giữa một hoạt động trên socket; thay vào đó, tùy thuộc vào ứng dụng (chủ đề A và B) để thương lượng việc sử dụng nó.

Nói chung, tốt nhất là thiết kế ứng dụng để chỉ một trong các chủ đề sẽ gọi recv() trên một ổ cắm duy nhất.

+0

Tôi nghĩ rằng bạn sai về các giả định của bạn ở đây. recv() nhận được một gói dữ liệu và thường được sử dụng với UDP, với TCP nó vẫn nhận được một gói dữ liệu nhưng trừ khi bạn đã rất cẩn thận bên phía người gửi, bạn có thể nhận được nội dung của hai ghi trong một recv. –

+0

Được rồi, tôi chỉ kiểm tra tài liệu và nó phức tạp hơn một gói tùy thuộc vào cờ, nhưng đó là những gì tôi đã quan sát như trường hợp thông thường trong các ứng dụng Linux mà tôi đã làm việc. –

+0

UDP datagrams chắc chắn an toàn hơn so với TCP luồng wrt chủ đề. Tôi không chắc chắn rằng họ đang 100% thread-an toàn, mặc dù - nếu bạn nhận được một EINTR (hiện vẫn còn xảy ra?), Sau đó thread A trở về từ recv() sớm, cho thread B một cơ hội để nhảy vào. –

2

Từ man page trên recv

Một recv() trên một ổ cắm SOCK_STREAM lợi nhuận càng nhiều thông tin có sẵn như kích thước của bộ đệm được cung cấp có thể giữ.

Giả sử bạn đang sử dụng TCP, vì nó không được chỉ định trong câu hỏi. Vì vậy, giả sử bạn có thread A và thread B cả hai đều chặn trên recv() cho socket s. Khi s có một số dữ liệu được nhận, nó sẽ bỏ chặn một trong các luồng, cho phép nói A và trả về dữ liệu. Dữ liệu được trả lại sẽ có kích thước ngẫu nhiên theo như chúng tôi quan tâm. Chủ đề A kiểm tra dữ liệu nhận được và quyết định xem nó có "thông báo" hoàn chỉnh hay không, trong đó thông báo là khái niệm mức ứng dụng.

Chủ đề A quyết định nó không có thông báo đầy đủ, vì vậy nó gọi recv() một lần nữa.NHƯNG trong khi chờ đợi B đã chặn trên cùng một ổ cắm và đã nhận được phần còn lại của "thông báo" được dành cho chủ đề A. Tôi đang sử dụng dự định ở đây một cách lỏng lẻo.

Bây giờ cả luồng A và chuỗi B có thông báo chưa hoàn chỉnh và sẽ tùy thuộc vào cách mã được viết, hãy ném dữ liệu đi không hợp lệ hoặc gây ra lỗi lạ và tinh tế.

Tôi ước tôi có thể nói rằng tôi không biết điều này từ kinh nghiệm.

Vì vậy, trong khi chính recv() là chủ đề an toàn về mặt kỹ thuật, bạn nên có hai luồng gọi đồng thời nếu bạn đang sử dụng nó cho TCP.

Theo như tôi biết, điều đó hoàn toàn an toàn khi bạn đang sử dụng UDP.

Tôi hy vọng điều này sẽ hữu ích.

Các vấn đề liên quan