2013-03-19 21 views
5

Đây là vấn đề: chương trình này sẽ nhận đầu vào từ stdin và đếm số byte được chèn vào; tín hiệu SIGUSR1 sẽ dừng chương trình chính và sẽ in ra lỗi chuẩn của tệp có bao nhiêu byte đã được sao chép khi tôi gửi SIGUSR1.Trình xử lý tín hiệu sẽ không thấy biến toàn cầu

Đó là cách giáo viên của tôi muốn tôi làm điều này: trong một loại thiết bị đầu cuối

cat /dev/zero | ./cpinout | cat >/dev/null 

trong khi đi từ trạm thứ hai gửi tín hiệu với

kill -USR1 xxxx 

trong đó xxxx là pid của cpinout.

tôi cập nhật mã trước đây của tôi:

/* cpinout.c */ 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <signal.h> 

#define BUF_SIZE 1024 

volatile sig_atomic_t countbyte = 0; 
volatile sig_atomic_t sigcount = 0; 

/* my_handler: gestore di signal */ 
static void sighandler(int signum) { 
    if(sigcount != 0) 
     fprintf(stderr, "Interrupted after %d byte.\n", sigcount); 
    sigcount = contabyte; 
} 

int main(void) { 

    int c; 
    char buffer[BUF_SIZE]; 
    struct sigaction action; 

    sigemptyset(&action.sa_mask); 
    action.sa_flags = 0; 
    action.sa_handler = sighandler; 
    if(sigaction(SIGUSR1, &action, NULL) == -1) { 
     fprintf(stderr, "sigusr: sigaction\n"); 
     exit(1); 
    } 
    while(c=getc(stdin) != EOF) { 
     countbyte++; 
     fputc(c, stdout); 
    } 
    return(0); 
} 
+0

Sẽ không làm việc ngay cả với sigaction> elmazzun

Trả lời

2


EDIT

Trong những ý kiến ​​bạn nói rằng bạn đang chạy các lệnh như:

cat /dev/zero | ./namefile | cat >/dev/null

Hành vi này là thực sự tốt. /dev/zero là một luồng không giới hạn số không, đang được gửi đến chương trình. Vì vậy, nó đếm chúng rất nhanh chóng. Khi bạn ngắt lời, nó dừng lại và bạn còn lại với một số lượng lớn.


Sự cố có thể liên quan đến việc xử lý tín hiệu có thể được gọi khi biến toàn cầu đang được cập nhật (nếu điều này có nhiều lệnh). Tuy nhiên, tài liệu GNU nói rằng an toàn để giả định rằng int luôn là nguyên tử trên hệ thống POSIX.

duy nhất khả năng khác mà tôi có thể nghĩ là bạn đang gọi điện thoại fputc trong vòng lặp, với printf trong xử lý (tuy nhiên nó phải được an toàn để gọi printf trong một handler nếu nó không được gọi bằng chương trình). Thử xóa fputc khỏi vòng lặp để xem liệu nó có giải quyết được sự cố hay không.

EDIT:

này xuất hiện để giải thích vấn đề. Điều này liên quan đến các loại chức năng mà được an toàn để gọi từ bên trong một xử lý tín hiệu:

Chức năng cũng có thể là nonreentrant nếu họ sử dụng cấu trúc dữ liệu tĩnh cho kế toán nội bộ của họ.Các ví dụ rõ ràng nhất của các hàm như vậy là các thành viên của thư viện stdio (printf(), scanf(), và vv), cập nhật cấu trúc dữ liệu nội bộ cho vùng đệm I/O. Vì vậy, khi sử dụng printf() từ bên trong bộ xử lý tín hiệu, chúng tôi có thể đôi khi thấy kết xuất lạ hoặc thậm chí là lỗi chương trình hoặc dữ liệu tham nhũng— nếu trình xử lý ngắt chương trình chính ở giữa thực hiện cuộc gọi đến printf () hoặc một chức năng stdio khác. (Linux Programming Interface)

chương trình của bạn được làm gián đoạn một hàm stdio, mà dường như để phù hợp này một cách hoàn hảo.


Dưới đây là một cách tiếp cận khác:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <signal.h> 

int countbyte = 0; // for main program 
int sigcount = 0; // for signal handler 

/* my_handler: signal handler */ 
static void sighandler(int signum) 
{ 
    sigcount = countbyte; 
} 

int main(void) 
{ 
    int c; 
    struct sigaction sigact; 

    sigemptyset(&sigact.sa_mask); 
    sigact.sa_flags = 0; 
    sigact.sa_handler = sighandler; 
    sigaction(SIGUSR1, &sigact, NULL); 
    while ((c = getc(stdin)) != EOF) { 
     countbyte++; 
     fputc(c, stdout); 
    } 
    if (sigcount != 0) { 
     printf("Interrupted after %d bytes\n", sigcount); 
    } 

    return 0; 
} 
+0

Ông có thể đưa ra một gợi ý lý do tại sao bạn nghĩ rằng sự khác biệt giữa tín hiệu và sigaction là thích hợp ở đây.? – AProgrammer

+0

@AProgrammer - trạng thái tài liệu 'Hành vi của tín hiệu() thay đổi theo các phiên bản UNIX, và cũng có nhiều lịch sử khác nhau trên các phiên bản Linux khác nhau. Tránh sử dụng nó: sử dụng sigaction (2) thay vào đó ... Việc sử dụng di động duy nhất của tín hiệu() là để thiết lập một tín hiệu của bố trí để SIG_DFL hoặc SIG_IGN. Các ngữ nghĩa khi sử dụng tín hiệu() để thiết lập trình xử lý tín hiệu khác nhau giữa các hệ thống (và POSIX.1 cho phép rõ ràng biến thể này); ** không sử dụng nó cho mục đích này. ** – teppic

+1

Có, có sự khác biệt về hành vi giữa các biến thể Unix, tôi biết không có gì liên quan đến vấn đề được báo cáo. – AProgrammer

3

Tín hiệu chỉ có thể viết volatile sig_atomic_t biến theo C89 và POSIX 7 tiêu chuẩn:

hành vi là undefined nếu xử lý tín hiệu dùng để chỉ bất kỳ đối tượng [ CX] [Tùy chọn bắt đầu] khác với errno [Tùy chọn kết thúc] với thời gian lưu trữ tĩnh khác hơn là chỉ định giá trị cho đối tượng được khai báo là biến động sig_atomic_t

Triển khai thường cung cấp nhiều hơn, nhưng tôi nghi ngờ rằng việc sử dụng các biến toàn cầu không biến động hoặc printf là một cái gì đó do bạn cung cấp.

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