2014-09-23 15 views
16

Tôi có this code để đọc từ Serial trong Linux, nhưng tôi không biết sự khác biệt giữa chặn và không chặn trong đọc Serial Port là gì và tốt hơn trong trường hợp nào?Linux Blocking vs. non Blocking Serial Đọc

+4

Nó hoàn toàn phụ thuộc vào kiến ​​trúc của ứng dụng của bạn. Chặn đơn giản hơn nhưng chặn. Không chặn cần mã hóa nhiều hơn một chút, nhưng cho phép bạn thực hiện một tác vụ khác trong cùng một thời điểm. –

Trả lời

41

Mã bạn đề cập là IMO được mã hóa và nhận xét kém. Mã đó không tuân thủ các thực tiễn POSIX về tính di động như được mô tả trong Setting Terminal Modes ProperlySerial Programming Guide for POSIX Operating Systems. Mã đó không đề cập đến rằng nó sử dụng chế độ không chuẩn (còn nguyên) và tái sử dụng thuật ngữ "chặn" và "không chặn" để mô tả thuộc tính VMINVTIME.

Định nghĩa thông thường về đọc "chặn" so với "không chặn" được dựa trên "khi" cuộc gọi đọc sẽ quay lại chương trình của bạn (và tiếp tục thực hiện với câu lệnh tiếp theo) và liệu dữ liệu được lưu trữ trong chương trình của bạn có đọc bộ đệm. Chế độ đọc chặn là chế độ mặc định, trừ khi yêu cầu không chặn bằng cách mở cổng nối tiếp bằng tùy chọn O_NONBLOCK hoặc O_NDELAY.

chế độ Canonical
Đối với một chặn canonical read tiếng gọi của một cổng nối tiếp, một dòng (aka kỷ lục) của văn bản sẽ luôn được trả lại trong bộ đệm được cung cấp (trừ khi một lỗi xảy ra). Cuộc gọi đọc sẽ chặn (tức là tạm ngừng thực hiện chương trình của bạn) cho đến khi nhận được và xử lý ký tự chấm dứt dòng.

Cuộc gọi đọc chuẩn không chặn của cổng nối tiếp sẽ luôn trả về "ngay lập tức". Việc đọc có thể hoặc không thể trả lại bất kỳ dữ liệu nào.
Nếu (kể từ cuộc gọi đọc trước) ít nhất một dòng văn bản đã được nhận và lưu trữ trong bộ đệm hệ thống, thì dòng cũ nhất sẽ bị xóa khỏi bộ đệm hệ thống và được sao chép vào bộ đệm của chương trình. Mã trả về sẽ cho biết độ dài dữ liệu.
Nếu (kể từ cuộc gọi đọc trước đó) một ký tự kết thúc dòng chưa được nhận và xử lý, thì không có dòng văn bản hoàn chỉnh nào khả dụng. Số đọc() sẽ trả về lỗi EAGAIN (tức là mã trả về -1 và errno được đặt thành EAGAIN). Sau đó, chương trình của bạn có thể thực hiện một số phép tính hoặc yêu cầu I/O từ một thiết bị khác hoặc trì hoãn/ngủ. Hoặc sau một sự chậm trễ tùy ý hoặc bằng cách thông báo bằng cách cuộc thăm dò ý kiến ​​() hoặc chọn(), chương trình của bạn có thể thử lại đọc().

không hợp chuẩn chế độ
Khi cổng nối tiếp được cấu hình cho chế độ phi kinh điển, các termiosc_cc phần tử mảng VMINVTIME nên được sử dụng để kiểm soát "chặn" , nhưng điều này yêu cầu cổng được mở ở chế độ chặn mặc định, tức là không chỉ định tùy chọn mở O_NONBLOCK. Nếu không, O_NONBLOCK sẽ được ưu tiên hơn thông số VMIN và VTIME và đọc() sẽ đặt errno tới EAGAIN và trả về -1 ngay lập tức thay vì 0 khi không có sẵn dữ liệu. (Đây là hành vi được quan sát thấy trong hạt nhân Linux 3.x gần đây, hạt nhân 2.6.x cũ hơn có thể hoạt động khác nhau.)

Trang termios người đàn ông mô tả (c_cc mảng index) VMIN như "số lượng tối thiểu của các nhân vật cho noncanonical đọc", và (c_cc index mảng) VTIME như "timeout tính bằng mili giây để đọc noncanonical ".
VMIN nên được điều chỉnh bằng chương trình của bạn để thích ứng với tin nhắn hoặc datagram dài điển hình được mong đợi và/hoặc kích thước tối thiểu cho dữ liệu để lấy & quá trình mỗi read().
VTIME nên được điều chỉnh bởi chương trình của bạn để phù hợp với mức độ bùng nổ điển hình hoặc tỷ lệ đến của dữ liệu nối tiếp dự kiến ​​và/hoặc thời gian tối đa để chờ dữ liệu hoặc dữ liệu.

Các giá trị VMINVTIME tương tác để xác định tiêu chí khi đọc phải trả về; ý nghĩa chính xác của chúng tùy thuộc vào ý nghĩa của chúng. Có bốn trường hợp có thể xảy ra.
This web page giải thích nó như:

  • VMIN = 0 và VTIME = 0

    Đây là một hoàn toàn non-blocking đọc - gọi là hài lòng ngay lập tức trực tiếp từ hàng đợi đầu vào của tài xế. Nếu dữ liệu có sẵn, nó được chuyển đến bộ đệm của người gọi lên đến nbyte và trả về. Nếu không thì số 0 sẽ được trả về ngay lập tức để chỉ ra "không có dữ liệu". Chúng tôi sẽ lưu ý rằng đây là "bỏ phiếu" của cổng nối tiếp và hầu như đó là ý tưởng tồi. Nếu được thực hiện nhiều lần, nó có thể tiêu thụ một lượng lớn thời gian xử lý và rất không hiệu quả. Không sử dụng chế độ này trừ khi bạn thực sự, thực sự biết những gì bạn đang làm.

  • VMIN = 0 và VTIME> 0

    Đây là một tinh khiết quá thời gian chờ đọc. Nếu dữ liệu có sẵn trong hàng đợi đầu vào, nó sẽ được chuyển đến bộ đệm của người gọi đến tối đa là nbyte và trả về ngay cho người gọi. Nếu không, trình điều khiển sẽ chặn cho đến khi dữ liệu đến, hoặc khi mười một VTIME hết hạn kể từ khi bắt đầu cuộc gọi. Nếu bộ đếm thời gian hết hạn mà không có dữ liệu, số không sẽ được trả về. Một byte đơn là đủ để đáp ứng cuộc gọi đọc này, nhưng nếu nhiều hơn có sẵn trong hàng đợi đầu vào, nó sẽ được trả lại cho người gọi. Lưu ý rằng đây là một bộ đếm thời gian tổng thể, không phải là một bộ đếm thời gian.

  • VMIN> 0 và VTIME> 0

    Một read() được thỏa mãn khi một trong hai nhân vật VMIN đã được chuyển giao cho bộ đệm của người gọi, hoặc khi VTIME phần mười hết hạn giữa các nhân vật. Vì bộ hẹn giờ này không được bắt đầu cho đến khi ký tự đầu tiên đến, cuộc gọi này có thể chặn vô thời hạn nếu dòng nối tiếp không hoạt động. Đây là phương thức hoạt động phổ biến nhất, và chúng tôi coi VTIME là thời gian chờ liên tục, không phải là tổng thời gian. Cuộc gọi này sẽ không bao giờ trả về số byte được đọc.

(Theo kinh nghiệm của tôi, các chế độ VMIN>0 and VTIME>0 không thực hiện khá công việc như đã quảng cáo.Bộ hẹn giờ có vẻ là một khoảng thời gian rất ngắn, ít hơn nhiều so với 1/10 giây. Tôi chưa thấy nó hoạt động trên ARM với 2.6 và Linux 3.13 trên x86. Với tốc độ baudrate nhanh (115200), với VMIN = 1 và VTIME = 1, một read() đôi khi trả về 10 hoặc nhiều byte. Nhưng thường thì nó chỉ là một phần đọc của một vài byte bất kể giá trị VTIME. Có lẽ sự vỡ nát này được ưa thích/mong muốn? Một tách nhắn 0,1 giây tối thiểu chỉ đơn giản là quá dài (và không thực tế) tại baudrates nhanh hiện đại.)

  • VMIN> 0 và VTIME = 0

    Đây là một đọc tính đó là hài lòng khi ở ít nhất các ký tự VMIN đã được chuyển vào bộ đệm của người gọi - không có thành phần thời gian nào liên quan. Đọc này có thể được đáp ứng từ hàng đợi đầu vào của trình điều khiển (nơi cuộc gọi có thể trở lại ngay lập tức), hoặc bằng cách đợi dữ liệu mới đến: trong trường hợp này cuộc gọi có thể chặn vô thời hạn. Chúng tôi tin rằng đó là hành vi không xác định nếu nbyte ít hơn VMIN.

mã mà bạn đề cập đến cấu hình "nonblocking" chế độ như VMIN = 0 và VTIME = 5. Điều này sẽ không gây ra việc đọc() trả về ngay lập tức như một đọc kinh điển không chặn đứng; với mã đó, một read() phải luôn đợi ít nhất một nửa giây trước khi trở về. Các định nghĩa thông thường của một "nonblocking" là chương trình gọi điện thoại của bạn không được preempted trong syscall và được kiểm soát trở lại (gần như) ngay lập tức. Để nhận được trả lại (vô điều kiện và) ngay lập tức (để đọc không chính thức), hãy đặt VMIN = 0 và VTIME = 0.

+0

Giải thích tốt, nhưng wow. Điều đó thành thật là một hợp đồng khá lộn xộn, so với [những gì Windows làm] (http://msdn.microsoft.com/en-us/library/windows/desktop/aa363190%28v=vs.85%29.aspx) –

+7

Điều đó mã pre-date POSIX trong vài năm, do đó, nó không có gì ngạc nhiên khi nó không khớp. – wallyk

+0

Nếu 'O_NONBLOCK' không được chỉ định ở chế độ không chuẩn, thì điều gì chỉ định' O_NONBLOCK' làm cho chế độ chuẩn? – CMCDragonkai