2010-10-07 35 views
6

Tôi có tình huống sau:Làm thế nào để gián đoạn cuộc gọi fread?

Có một chủ đề đọc từ một thiết bị có cuộc gọi fread. Cuộc gọi này đang chặn miễn là không có dữ liệu gửi từ thiết bị. Khi tôi dừng chủ đề này, nó vẫn treo trong chủ đề này.

Bây giờ tôi thấy như sau bên trong man page của fread:

LỖI

Trên tất cả các hệ thống phù hợp với các Độc UNIX Specification, các fread() chức năng đặt errno như được liệt kê cho các điều kiện sau đây: :

[EINTR] Thao tác đọc là bị chấm dứt do nhận đượcTín hiệuvà không có dữ liệu nào được chuyển.

Điều đó có nghĩa là có cách để làm gián đoạn cuộc gọi từ một chuỗi khác. Nhưng tôi không biết làm thế nào. Ai đó có thể cho tôi biết làm thế nào để gửi một tín hiệu để làm gián đoạn cuộc gọi fread? Và tôi cần gửi tín hiệu gì?


Cập nhật 08-10-10 09:25

tôi vẫn chưa nhận được nó để làm việc. Tôi đã thử kill() và pthread_kill() với các tín hiệu khác nhau. Nhưng dường như không có gì làm gián đoạn cuộc gọi fread(). Điều duy nhất mà tôi làm việc là giết chết toàn bộ ứng dụng, nhưng đó không phải là điều tôi muốn.

+3

Thú vị rằng điều này phải làm với đồng thời: Tôi đã hiểu sai 'fread' là một chuỗi" Cockney ". –

Trả lời

3

Hãy xem man 2 kill. (Hoặc xem here)

Tôi có cảm giác rằng bạn không muốn làm điều này, mặc dù - hầu hết mọi người bỏ qua errno EINTR và đọc lại. Bạn có thể muốn xem xét các lần đọc không chặn.

+0

Bạn có thể cho tôi biết tín hiệu nào tôi cần gửi đi bằng lệnh gọi hệ thống kill() để ngắt fread() không? –

+0

Nói chung, mọi tín hiệu sẽ làm gián đoạn cuộc gọi 'fread()'. Điều đó nói rằng, nói chung, nhiều tín hiệu thường sẽ giết chết ứng dụng của bạn (ngoại trừ SIGCONT). Tôi sẽ sử dụng SIGHUP hoặc một trong những tín hiệu do người dùng xác định. Nhưng như tôi đã nói trong câu trả lời của tôi, tôi cũng thường không thích sử dụng tín hiệu ở tất cả cho mục đích này. (Xem câu trả lời của John Marshall để thay thế) –

+2

Ngoài việc tạo tín hiệu từ một luồng khác bằng 'kill', chức năng' báo thức 'thường được sử dụng để chặn cuộc gọi chặn 'đọc' thành hết giờ. –

0

Bạn có thể sử dụng tòa nhà chọc trời kill().

CẬP NHẬT

Hóa ra tôi không nhận định câu hỏi của bạn. Như R. đã chỉ ra bên dưới, kill() chỉ dành cho quá trình giết, không phải chủ đề.

+0

Bạn có thể cho tôi biết tín hiệu nào tôi cần gửi đi bằng lệnh gọi hệ thống kill() để ngắt fread() không? –

+3

Nó phải là một tín hiệu mà trước đó bạn đã thiết lập một trình xử lý tín hiệu (xem 'sigaction()') và có * not * sử dụng cờ 'SA_RESTART'. – mark4o

+1

'kill' sẽ không hoạt động. Bạn cần 'pthread_kill' có thể gửi tín hiệu đến một chuỗi cụ thể. –

4

Bạn thực sự muốn đọc về cuộc gọi hệ thống select(2), cho phép bạn tìm hiểu xem có dữ liệu có sẵn trên bộ mô tả tệp đó hay không mà không chặn trên thiết bị đó.

+0

Trong khi chọn() sẽ hữu ích, nó không thực sự trả lời câu hỏi. –

+2

@Michael Foukarakis - Do bối cảnh, câu hỏi có thể yêu cầu [giải pháp sai cho vấn đề lớn hơn] (http://www.perlmonks.org/index.pl?node_id=542341). John đưa ra một câu trả lời hợp lý để giúp OP đạt được mục tiêu của mình bằng cách giải quyết vấn đề lớn hơn. Downvote có vẻ hơi khắc nghiệt. – bstpierre

+0

Tôi không thể đánh giá giải pháp mà không biết vấn đề, phải không? Có lẽ OP * có * để sử dụng 'fread()'. Tôi không biết, và tôi không muốn giả định. –

2

Trong chuỗi, thay vì chặn bằng fread, hãy chặn với select. Khi select trả lại, hãy kiểm tra biến "tôi đã hoàn tất". Nếu không được thực hiện, bạn có thể gọi fread để nhận dữ liệu.

Từ chủ đề khác - muốn dừng chuỗi chỉ đường - bạn có thể đặt biến "tôi đã thực hiện" và sau đó đóng fd sao cho sợi chỉ cần đánh thức từ select ngay lập tức.

Nếu ngữ cảnh cấm bạn đóng fd (bạn đề cập bạn đang đọc từ thiết bị nhưng nói rằng bạn có ổ cắm bạn muốn mở), bạn có thể mở fd thứ hai mà bạn viết từ chủ đề khác thức dậy select.

Như được đề xuất trong các nhận xét bên dưới, đóng fd để đánh thức select có thể không di động. Bạn có thể sử dụng chiến lược thứ hai fd được đề cập ở trên để đạt được điều này một cách dễ dàng hơn.

+0

Hoặc bạn có thể 'đóng()' fd được chuyển tới 'select()' để hủy nó ngay lập tức, thay vì bằng cách sử dụng bộ nhớ cache chuyển đổi bối cảnh-thiếu logic bỏ phiếu lãng phí pin. –

+0

@Ben Voigt - Cảm ơn bạn đã chỉ ra điều đó. Đã chỉnh sửa câu trả lời của tôi cho phù hợp. – bstpierre

+0

@Ben: très mát mẻ, nhưng nó được chỉ định để làm việc theo cách đó? Tôi lướt qua các phần chọn (2) và Chủ đề của thông số SUS, nhưng không nhận thấy bất kỳ mô tả nào về những gì mong đợi sẽ thấy khi một fd biến mất khỏi nó trong khi select() đang chặn. OTOH Tôi cho rằng một cái gì đó hợp lý đã xảy ra tốt hơn hoặc khác có tiềm năng để khai thác ... –

9

1. Tín hiệu:

Sử dụng tín hiệu, như nhiều người khác chỉ ra, có thể làm việc. Tuy nhiên, như nhiều người khác cũng chỉ ra, phương pháp tiếp cận có nhược điểm của nó.

2. Chọn():

Sử dụng lựa chọn() (hoặc chức năng ghép kênh khác), bạn có thể chặn chờ đợi dữ liệu đến từ nhiều hơn một bộ mô tả tập tin, và chỉ định một thời gian chờ.

Sử dụng thời gian chờ cho lợi thế của bạn. Bất cứ khi nào select() trả về, hãy kiểm tra một biến toàn cục để xem bạn có phải chấm dứt hay không. Nếu bạn muốn phản ứng ngay lập tức, hãy tiếp tục đọc.

3. Chọn() và ống dẫn:

Nhiều FDS có nghĩa là bạn có thể chờ cho dữ liệu đến thông qua các thiết bị mà bạn đề cập và, nói, một đường ống.

Trước khi tạo chủ đề, tạo một đường ống, sau đó có khối chuỗi trên select() theo dõi cả thiết bị và đường ống. Bất cứ khi nào bạn muốn bỏ chặn, hãy chọn một thiết bị có dữ liệu mới hay không, gửi một byte xuống đường ống.

Nếu chọn() cho bạn biết nó đã bỏ chặn do dữ liệu đến qua đường ống, bạn có thể dọn dẹp và chấm dứt. Lưu ý phương pháp này linh hoạt hơn nhiều so với phương thức báo hiệu, vì bạn có thể, ngoài việc chỉ sử dụng đường ống làm phương thức đánh thức, hãy sử dụng nó để chuyển các thông tin hoặc lệnh hữu ích.

4. Chọn(), ống và các tín hiệu:

Nếu bạn đang sử dụng nhiều quy trình và không muốn/không thể vượt qua xung quanh một đường ống, bạn có thể kết hợp cả hai giải pháp. Tạo một đường ống và cài đặt trình xử lý tín hiệu cho SIGUSR1. Trong trình xử lý tín hiệu, gửi một byte xuống đường ống.

Bất cứ khi nào một quá trình gửi SIGUSR1, trình xử lý sẽ được gọi và bỏ chặn select(). Bằng cách kiểm tra các fdsets, bạn sẽ biết nó không vì lý do nào khác hơn là chương trình của chính bạn báo hiệu chính nó.

+0

Sẽ không' select() 'không đủ vì' fread() 'có thể thực hiện nhiều cuộc gọi tới 'read()'? Tôi tự hỏi nếu có thể nhận được dòng vào một trạng thái lỗi trong một bộ xử lý tín hiệu sẽ làm việc ... – binki

0

Trình xử lý tín hiệu sẽ không làm gián đoạn fread trừ khi chúng được cài đặt làm gián đoạn và các tín hiệu không được ngắt sẽ không bao giờ bị gián đoạn. Tiêu chuẩn POSIX cho phép các trình xử lý được cài đặt theo chức năng signal bị gián đoạn hoặc gián đoạn theo mặc định (và trên Linux mặc định là không gián đoạn), vì vậy nếu bạn cần một hành vi cụ thể, hãy sử dụng chức năng sigaction và chỉ định mong muốn sa_flags. Cụ thể, bạn cần bỏ qua cờ SA_RESTART.Ví dụ:

struct sigaction sa = { .sa_handler = dummy_func, .sa_flags = 0 }; 
sigaction(SIGUSR1, &sa, 0); 

Lưu ý rằng sa_flags sẽ mặc nhiên là 0 anyway nếu bỏ qua, nhưng tôi bao gồm nó một cách rõ ràng trong initializer để minh họa. Sau đó, bạn có thể làm gián đoạn số fread bằng cách gửi SIGUSR1 với kill hoặc pthread_kill.

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