Linux程序开发(七):alarm /setitimer 编写文字时钟程序

发布于:2024-05-22 ⋅ 阅读:(167) ⋅ 点赞:(0)

Tips:"分享是快乐的源泉💧,在我的博客里,不仅有知识的海洋🌊,还有满满的正能量加持💪,快来和我一起分享这份快乐吧😊!

喜欢我的博客的话,记得点个红心❤️和小关小注哦!您的支持是我创作的动力!数据源存放在我的资源下载区啦!

Linux程序开发(七):alarm /setitimer 编写文字时钟程序

1. 问答题

1.1. 简述什么是可靠信息和不可靠信息,并试验验证SIGINT是可靠还是不可靠信息。

在Linux中,可靠信息是指在传输过程中不会丢失、重复或损坏的数据,而不可靠信息则可能会遇到这些问题。通常,TCP协议下的数据传输被认为是可靠信息,而UDP协议下的数据传输则被认为是不可靠信息。

SIGINT是一个信号,用于请求进程停止运行。在Linux中,SIGINT被认为是可靠信息,因为它可以保证被接收并执行相应的操作。例如,在终端中按下Ctrl+C会发送SIGINT信号给正在运行的程序,程序会接收到信号并停止运行。

2. 编程题

2.1. 编写程序实现如下功能:

  1. 程序A(A.c)按照用户输入的时间参数定时向程序B(B.c)发送信号,B.c程序接收到该信号后,打印输出一条信息并结束,运行示例如下:
  2. 先后台运行程序B;再运行A,A有两个参数,第一个是B的进程号(可以从命令ps -uax|grep B获取),第二个是定时时间(秒)。

运行示例:

$ ./B &
[9] 8329
$ ./A 8329 3
A: After 3 seconds, send a SIGALRM signal myself.
A: Sending a signal to process 8329...
B: Receiving a SIGINT signal.

编写C语言程序A.c

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

int target_pid;
int seconds;

void send_signal()
{
    printf("A: Sending a signal to process %d...\n", target_pid);
    kill(target_pid, SIGINT); // 发送信号
}

void sig_handler(int signo)
{
    if (signo == SIGALRM)
        printf("A: After %d seconds, send a SIGALRM signal myself.\n", seconds);
    else if (signo == SIGINT)
    {
        printf("A: Received a SIGINT signal from B, exiting...\n");
        exit(0);
    }
}

int main(int argc, char *argv[])
{
    if (argc != 3) {
        printf("Usage: %s <pid> <seconds>\n", argv[0]);
        exit(1);
    }

    target_pid = atoi(argv[1]);
    seconds = atoi(argv[2]);

    if (signal(SIGALRM, sig_handler) == SIG_ERR)
        perror("signal");

    if (signal(SIGINT, sig_handler) == SIG_ERR)
        perror("signal");

    alarm(seconds); // 设置定时器

    printf("A: Program started, will send a signal after %d seconds.\n", seconds);
    sleep(seconds); // 等待定时器到期

    send_signal(); // 发送信号

    while (1)
        ; // 等待SIGINT信号
}

编写C语言程序B.c

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

void sig_handler(int signo)
{
    printf("B: Receiving a SIGINT signal.\n");
    exit(0);
}

int main()
{
    if (signal(SIGINT, sig_handler) == SIG_ERR)
        perror("signal");

    printf("B: Program started, waiting for a signal...\n");

    while (1)
        ; // 等待信号
}

运用gcc编译器进行程序编译

gcc -o A A.c
gcc -o B B.c

在这里插入图片描述

运行程序

./B &
[1] 3025
./A 3025 3
A: After 3 seconds, send a SIGALRM signal myself.
A: Sending a signal to process 3025...
B: Receiving a SIGINT signal.

在这里插入图片描述

2.2. 编写一个程序,实现以下功能:由父进程创建两个子进程,通过在终端输入“Ctrl+\”组合键向父进程发送SIGQUIT信号;父进程接收到这个信号后,向其两个子进程分别发送整数值为35的信号,子进程获得对应的信号后,终止运行;父进程调用wait函数等待两个子进程都终止后,再自我终止。

编写C语言程序signal_handling.c

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

void child_signal_handler(int signo)
{
    printf("Child process %d received signal %d, terminating...\n", getpid(), signo);
    exit(0);
}

void parent_signal_handler(int signo)
{
    printf("Parent process %d received SIGQUIT signal, sending signals to child processes...\n", getpid());

    // 向两个子进程发送信号
    kill(0, SIGUSR1);

    // 等待子进程终止
    wait(NULL);
    wait(NULL);

    printf("All child processes terminated, parent process %d exiting...\n", getpid());
    exit(0);
}

int main()
{
    pid_t child1, child2;

    // 创建第一个子进程
    child1 = fork();
    if (child1 == 0)
    {
        // 子进程1
        signal(SIGUSR1, child_signal_handler);
        while (1)
            ; // 持续等待信号
        exit(0);
    }

    // 创建第二个子进程
    child2 = fork();
    if (child2 == 0)
    {
        // 子进程2
        signal(SIGUSR1, child_signal_handler);
        while (1)
            ; // 持续等待信号
        exit(0);
    }

    // 父进程
    signal(SIGQUIT, parent_signal_handler);

    printf("Parent process %d created child processes %d and %d\n", getpid(), child1, child2);
    printf("Press Ctrl+\\ to send SIGQUIT signal to parent process %d\n", getpid());

    while (1)
        ; // 持续等待信号

    return 0;
}

运用gcc编译器进行程序编译

gcc -o signal_handling signal_handling.c

在这里插入图片描述

运行程序

./signal_handling

在这里插入图片描述

2.3. 编写一个程序,实现以下功能:

  1. 搜索2~65535之间所有的素数并将其保存到数组中;
  2. 用户输入ctrl+c发出信号,程序打印出最近找到的素数,并继续搜索;
  3. 用户输入ctrl+\发出信号,程序退出运行,并打印出所有已找到的素数;
  4. 如没有发出信号,程序打印所有找到素数

编写C语言程序prime_search.c

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>

int i = 1, a[30000], j = 0;

void sigHandler(int signalNum)
{
    printf("最近找到的素数: %d\n", a[j - 1]);
}

int isPrime(int n)
{ // 判断n是否为素数
    if (n == 1)
        return 0;
    if (n == 2)
        return 1;
    if (n % 2 == 0)
        return 0; // 排除所有偶数

    for (int i = 3; i * i <= n; i += 2) // 只需要判断奇数
        if (n % i == 0)
            return 0;
    return 1;
}

int main()
{
    signal(SIGINT, sigHandler);

    while (i <= 65535)
    {
        if (isPrime(i))
            a[j++] = i;

        i++;
        sleep(2);
    }

    return 0;
}

运用gcc编译器进行程序编译

gcc -std=c99 -o prime_search prime_search.c

在这里插入图片描述

运行程序

./prime_search
1. 用户输入ctrl+c发出信号,程序打印出最近找到的素数,并继续搜索;
2. 用户输入ctrl+\发出信号,程序退出运行,并打印出所有已找到的素数;
3. 如没有发出信号,程序打印所有找到素数

在这里插入图片描述

在这里插入图片描述

2.4. 利用alarm函数(也可以利用setitimer函数)编写文字时钟程序,实现数字时钟功能。printf输出利用\033格式化输出彩色文字时钟,格式自拟。

编写C语言程序``alarm_time.c`

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>

void print_clock() {
    time_t rawtime;
    struct tm * timeinfo;

    time(&rawtime);
    timeinfo = localtime(&rawtime);

    // 格式化输出彩色文字时钟
    printf("\033[2J");  // 清屏
    printf("\033[1;1H");  // 移动光标到屏幕左上角
    printf("\033[1;33m");  // 设置颜色为黄色
    printf("%02d:%02d:%02d\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
    printf("\033[0m");  // 恢复默认颜色
}

void sigHandler(int signalNum) {
    print_clock();
    alarm(1);
}

int main() {
    signal(SIGALRM, sigHandler);
    alarm(1);

    while (1) {
        pause();
    }

    return 0;
}

运用gcc编译器进行程序编译

gcc -o alarm_time alarm_time.c

在这里插入图片描述

运行程序

./alarm_time

在这里插入图片描述

在这里插入图片描述