2012-04-10 47 views
5

Tôi đã tự hỏi nếu nó có thể bị gián đoạn bởi một tín hiệu khi chương trình của tôi là xử lý tín hiệu khác cùng một lúc, tôi đã cố gắng để mô phỏng nó với:tín hiệu xử lý trong C - ngắt trong ngắt

#include<signal.h> 
#include<stdlib.h> 
#include<stdio.h> 
#include<unistd.h> 
#include<sys/wait.h> 
#include<string.h> 

void sig_output() 
{ 
    sigset_t set; 
    sigprocmask(0,NULL,&set); 
    printf("currently blocking:"); 
    if (sigismember(&set,SIGUSR1)) 
     printf("\nSIGUSR1"); 
    if(sigismember(&set,SIGUSR2)) 
     printf("\nSIGUSR2"); 
    printf("\n"); 
    return ; 
} 

void sig_handler(int sig) 
{ 
    raise(SIGUSR1);  
    printf("start\n"); 
    if (sig==SIGUSR1) 
     printf("SIGUSR1\n"); 
    else if (sig==SIGUSR2) 
     printf("SIGUSR2\n"); 
    printf("end\n"); 
    return ; 
} 

void other_sig_handler(int sig) 
{ 
    printf("start - other\n"); 
    if (sig==SIGUSR1) 
     printf("SIGUSR1\n"); 
    else if (sig==SIGUSR2) 
     printf("SIGUSR2\n"); 
    printf("end - other\n"); 
    return ; 
} 

int main() 
{ 
    sig_output(); 
    struct sigaction a; 
    a.sa_handler=sig_handler; 
    a.sa_flags=0; 
    sigset_t set,old; 
    //blocking SIGUSR1,SIGUSR2 
    sigemptyset(&set); 
    sigaddset(&set,SIGUSR1); 
    sigaddset(&set,SIGUSR2); 
    printf("blocking SIGUSR1, SIGUSR2\n"); 
    sigprocmask(SIG_SETMASK,&set,&old); 
    sig_output(); 
    //adding handles for SIGUSR1,SIGUSR2 
    sigemptyset(&(a.sa_mask)); 
    sigaction(SIGUSR1,&a,NULL); 
    a.sa_handler=other_sig_handler; 
    sigaction(SIGUSR2,&a,NULL); 
    printf("poczatek wysylania \n"); 
    raise(SIGUSR1); 
    raise(SIGUSR2); 
    raise(SIGUSR1); 
    printf("using sigsuspend\n"); 
    sigsuspend(&old); 
    printf("end of program\n"); 
    return 0; 
} 

và mỗi khi tôi chạy chương trình này, tôi nhận được

currently blocking: 
blocking SIGUSR1, SIGUSR2 
currently blocking: 
SIGUSR1 
SIGUSR2 
raising 
using sigsuspend 
start - other 
SIGUSR2 
end - other 
start 
SIGUSR1 
end 
end of program 

luôn luôn như vậy?

+0

Nó thực sự phụ thuộc vào bộ xử lý và hệ điều hành. Nói chung, nhiều CPU hỗ trợ các mức độ ưu tiên khác nhau cho các ngắt như vậy mà ngắt ưu tiên cao hơn có thể nhảy vào trong khi mức ưu tiên thấp hơn chạy. – TJD

+5

Tín hiệu POSIX không phải là ngắt phần cứng, do đó chính bộ xử lý không có vấn đề ở đây. – torek

Trả lời

6

Trích dẫn các sigaction(2) manpage:

thói quen tín hiệu bình thường thực hiện với tín hiệu gây ra gọi của họ bị chặn, nhưng các tín hiệu khác nhưng có thể xảy ra. Mặt nạ tín hiệu toàn cầu xác định nhóm tín hiệu hiện bị chặn từ quá trình phân phối đến quá trình. Mặt nạ tín hiệu cho quy trình được khởi tạo từ mặt nạ của phụ huynh (thường trống). Nó có thể được thay đổi với cuộc gọi sigprocmask(2) hoặc khi tín hiệu được gửi đến quy trình.

Bạn có thể kiểm soát liệu tín hiệu có bị chặn tự động trong trình xử lý tín hiệu với cờ SA_NODEFER hay không.

+0

Ok, tôi phải bỏ lỡ một chút thông tin. – Andna

+1

Nó cũng đáng chú ý (tôi nghĩ rằng nó không rõ ràng từ tài liệu, mặc dù nó * là * khá hợp lý) rằng 'sa_mask' bạn cung cấp cho' sigaction' là một mặt nạ của * thêm * tín hiệu để chặn, không phải là một mặt nạ mới bộ. Vì vậy, nếu bạn (1) yêu cầu bắt tín hiệu X với 'sa_mask' chặn tín hiệu Y (và ngầm chặn X vì bạn tắt' SA_NODEFER'), sau đó (2) sử dụng 'sigprocmask' để chặn tín hiệu Z, sau đó (3) thực sự bắt một tín hiệu X, xử lý của bạn chạy với tất cả các X, Y, và Z bị chặn. – torek

+0

Nó có thể không rõ ràng từ tài liệu Linux; tài liệu OS X (qua FreeBSD) là khá rõ ràng về cách mặt nạ mới được hình thành. – geekosaur

5

Thứ tự mà các tín hiệu đang chờ xử lý cụ thể này được phân phối không, theo như tôi đã biết, được xác định. Tuy nhiên, tín hiệu (chủ yếu, có ngoại lệ cho SIGCLD, được thực hiện theo cách truyền thống bằng cách "gian lận"), không phải xếp hàng ", ngoại trừ tín hiệu thời gian thực. Khía cạnh không xếp hàng có nghĩa là nếu bạn có tín hiệu X bị chặn, và sau đó raise nó hai lần (như bạn làm ở trên cho SIGUSR1), bạn chỉ nhận được nó được gửi một lần.

Trật tự chỉ ghi trên ít nhất một hệ thống (hệ điều hành MacOS) là:

If multiple signals are ready to be delivered at the same time, any signals that 
could be caused by traps are delivered first. 

(Đây là những thứ như SIGSEGVSIGBUS.) Nói chung, bạn có thể kiểm soát trật tự giao hàng bằng cách sử dụng tín hiệu mặt nạ chặn: bỏ chặn bất kỳ (các) tín hiệu cụ thể nào tại một số điểm và đó là những tín hiệu có thể được phân phối tại thời điểm đó.

Nếu bạn không đặt SA_NODEFER, mặt nạ chặn tại mục nhập cho trình xử lý của bạn sẽ luôn chặn bất kỳ tín hiệu nào mà trình xử lý của bạn đang xử lý để bạn không phải lo lắng về việc đệ quy.

Trường hợp đặc biệt cho SIGCLD đến từ Hệ thống V, ban đầu được triển khai bằng cách đặt lại trình xử lý thành SIG_DFL trên mỗi giao hàng SIGCLD. (Trong thực tế, SysV đã làm điều này với tất cả các tín hiệu, thực hiện hiệu quả SA_RESETHAND cho dù bạn có muốn hay không.) Hành động mặc định là hủy bỏ tín hiệu, như thể trình xử lý là SIG_IGN. Điều này tất nhiên tạo ra điều kiện chủng tộc khi nhiều quá trình con hoàn thành trước khi xử lý có thể làm điều đó. Thay vì một mô hình chặn/bỏ chặn, mặc dù, các SysV folks đặt trong một hack: ở phần cuối của xử lý SIGCLD của bạn, bạn sẽ gọi signal(SIGCLD, handler); để sửa chữa xử lý. Tại thời điểm đó, nếu có bất kỳ trẻ em nào chưa được thoát khỏi số chưa được wait cho, SysV sẽ lập tức tạo mớiSIGCLD và trình xử lý của bạn sẽ được nhập theo cách đệ quy. Điều này làm cho nó trông giống như các tín hiệu được xếp hàng đợi, mà không thực sự xếp hàng chúng.

Để biết thêm về tín hiệu Linux, hãy xem (ví dụ) http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html.