UNP函数笔记十五: 信号驱动式I/O

本文提供了一个使用信号驱动I/O进行数据报接收与回显的C语言程序示例。该程序通过设置SIGIO信号来通知主进程处理接收到的数据报,并采用信号处理函数实现数据读取。此外,还展示了如何利用信号集进行信号阻塞与恢复。

第二十五章  信号驱动式I/O:


示例:

#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>

#include "err_exit.h"
#include "my_signal.h"

static int  sockfd;

#define    QSIZE       8  /* size of input queue */
#define    MAXDG    4096  /* max datagram size */

typedef struct {
    void            * dg_data;   /* ptr to actual datagram */
    size_t            dg_len;    /* length of datagram */
    struct sockaddr * dg_sa;     /* ptr to sockaddr{} w/client's address */
    socklen_t         dg_salen;  /* length of sockaddr{} */
} DG;

static DG     dg[QSIZE];         /* queue of datagrams to process */
static long   cntread[QSIZE+1];  /* diagnostic counter */

static int       iget;    /* next one for main loop to process */
static int       iput;    /* next one for signal handler to read into */
static int       nqueue;  /* on queue for main loop to process */
static socklen_t clilen;  /* max length of sockaddr{} */

void 
sig_io(int signo)
{
    ssize_t   len;
    int       nread;
    DG      * ptr;

    for (nread = 0; ; ) {
        if (nqueue >= QSIZE) {
            printf("receive overflow\n");
            exit(1);
        }

        ptr = &dg[iput];
        ptr->dg_salen = clilen;
        len = recvfrom(sockfd, ptr->dg_data, MAXDG, 0,
                       ptr->dg_sa, &ptr->dg_salen);
        if (len < 0) {
            if (errno == EWOULDBLOCK) {
                break;  /* all done; no more queued to read */
            }
            else {
                err_exit("recvfrom error");
            }
        }
        ptr->dg_len = len;

        nread++;
        nqueue++;
        if (++iput >= QSIZE) {
            iput = 0;
        }
    }
    cntread[nread]++;  /* histogram of datagrams read per signal */
}

void 
sig_hup(int signo)
{
    int  i;

    for (i = 0; i <= QSIZE; i++) {
        printf("cntread[%d] = %ld\n", i, cntread[i]);
    }
}

void 
dg_echo(int sockfd_arg, struct sockaddr * pcliaddr, socklen_t clilen_arg)
{
    int        i;
    const int  on = 1;
    sigset_t   zeromask;
    sigset_t   newmask;
    sigset_t   oldmask;

    sockfd = sockfd_arg;
    clilen = clilen_arg;

    for (i = 0; i < QSIZE; i++) {  /* init queue of buffers */
        if ((dg[i].dg_data = malloc(MAXDG)) == NULL) {
            err_exit("malloc error");
        }
        if ((dg[i].dg_sa = (struct sockaddr *)malloc(clilen)) == NULL) {
            err_exit("malloc error");
        }
        dg[i].dg_salen = clilen;
    }
    iget = iput = nqueue = 0;

    if (my_signal(SIGHUP, sig_hup) == SIG_ERR) {
        err_exit("my_signal error");
    }
    if (my_signal(SIGIO, sig_io) == SIG_ERR) {
        err_exit("my_signal error");
    }
    if (fcntl(sockfd, F_SETOWN, getpid()) == -1) {
        err_exit("fcntl error");
    }
    if (ioctl(sockfd, FIOASYNC, &on) == -1) {
        err_exit("ioctl error");
    }
    if (ioctl(sockfd, FIONBIO, &on) == -1) {
        err_exit("ioctl error");
    }

    /* init three signal sets */
    if (sigemptyset(&zeromask) == -1) {
        err_exit("sigemptyset error");
    }
    if (sigemptyset(&oldmask) == -1) {
        err_exit("sigemptyset error");
    }
    if (sigemptyset(&newmask) == -1) {
        err_exit("sigemptyset error");
    }
    /* signal we want to block */
    if (sigaddset(&newmask, SIGIO) == -1) {
        err_exit("sigaddset error");
    }

    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) == -1) {
        err_exit("sigprocmask error");
    }
    for ( ; ; ) {
        while (nqueue == 0) {
            sigsuspend(&zeromask);  /* wait for datagram to process */
        }

        /* unblock SIGIO */
        if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) {
            err_exit("sigprocmask error");
        }
        if (sendto(sockfd, dg[iget].dg_data, dg[iget].dg_len, 0,
                   dg[iget].dg_sa, dg[iget].dg_salen) == -1) {
            err_exit("sendto error");
        }

        if (++iget >= QSIZE) {
            iget = 0;
        }

        /* block SIGIO */
        if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) == -1) {
            err_exit("sigprocmask error");
        }
        nqueue--;
    }
}

### 问题分析 执行 `git pull origin master --allow-unrelated-histories` 时,可能会遇到多种错误。根据提供的引用内容[^1],错误可能源于以下原因: - **本地和远程分支的历史记录不相关**:Git 默认不允许合并两个没有共同祖先的分支。 - **本地修改冲突**:如果本地文件被修改但未提交,Git 会拒绝拉取操作以避免数据丢失[^5]。 - **强制推送或合并策略问题**:在某些情况下,简单的拉取命令可能无法解决问题,需要手动合并或强制推送[^3]。 --- ### 解决方案 以下是针对该问题的详细解决方法: #### 方法一:允许不相关历史记录并强制合并 可以使用 `--allow-unrelated-histories` 参数来允许合并两个没有共同祖先的分支。具体步骤如下: ```bash # 确保本地分支是最新的 git fetch origin # 执行合并操作 git merge origin/master --allow-unrelated-histories ``` 如果上述命令仍然报错,可能是因为存在未解决的冲突或本地修改[^2]。 --- #### 方法二:撤销本地修改后重新拉取 如果本地存在未提交的修改,可能导致拉取失败。可以通过以下步骤解决: ```bash # 查看当前修改状态 git status # 撤销本地修改(注意:此操作将丢弃未提交的更改) git checkout . # 或者重置到最近一次提交(更彻底的方式) git reset --hard HEAD # 再次尝试拉取 git pull origin master --allow-unrelated-histories ``` 需要注意的是,`git checkout .` 和 `git reset --hard HEAD` 都会丢弃未提交的更改,请确保重要更改已备份。 --- #### 方法三:创建新分支拉取 如果本地分支已经严重冲突或不想覆盖现有内容,可以创建一个新分支来拉取远程内容: ```bash # 创建并切换到新分支 git checkout -b new-branch # 拉取远程内容 git pull origin master --allow-unrelated-histories ``` 这种方式可以避免对现有分支的干扰,适合处理复杂冲突场景。 --- #### 方法四:手动合并远程分支 如果自动合并失败,可以手动合并远程分支的内容: ```bash # 获取远程分支的最新内容 git fetch origin # 手动合并远程分支 git merge origin/master ``` 如果有冲突,Git 会提示冲突文件的位置。编辑这些文件解决冲突后,继续完成合并: ```bash # 标记冲突已解决 git add <冲突文件> # 完成合并 git commit ``` --- #### 方法五:强制推送(谨慎使用) 如果确定本地分支是正确的,并且希望覆盖远程分支的内容,可以使用以下命令: ```bash git push --force origin master ``` 此操作会直接覆盖远程分支的历史记录,可能导致数据丢失,需谨慎使用[^3]。 --- ### 注意事项 1. **备份重要数据**:在执行任何可能破坏数据的操作前,请确保已备份重要数据。 2. **检查分支关系**:确认本地和远程分支是否确实没有共同祖先,避免误用 `--allow-unrelated-histories`。 3. **团队协作**:在多人协作环境中,强制推送可能会导致其他成员的工作丢失,建议优先使用合并方式。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值