c非标准库参考4-信号和管道

sleep(让进程暂停执行一段时间)

#include <unistd.h>
unsigned int sleep(unsigned int seconds);

sleep()会令目前的进程暂停,直到达到参数seconds所指定的时间,或是被信号所中断。

若进程暂停到参数seconds所指定的时间则返回0,若有信号中断则返回剩余秒数。

pause(让进程暂停直到信号出现)

#include <unistd.h>
int pause(void);

Suspend the process until a signal arrives.
This always returns -1 and sets `errno’ to EINTR.

alarm(设置信号传送闹钟)

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。

返回之前闹钟的剩余秒数,如果之前未设闹钟则返回0。

kill(传送信号给指定的进程)

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

kill()可以用来送参数sig指定的信号给参数pid指定的进程。参数pid有几种情况:
pid>0 将信号传给进程识别码为pid的进程
pid=0 将信号传给和目前进程相同进程组的所有进程
pid=-1 将信号广播传送给系统内所有的进程
pid<0 将信号传给进程组识别码为pid绝对值的所有进程

执行成功则返回0,如果有错误则返回-1。
EINVAL 参数sig不合法
ESRCH 参数pid所指定的进程或进程组不存在
EPERM 权限不够无法传送信号给指定进程

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
        pid_t pid;
        int status;
        if(!(pid=fork())){
                printf("Hi I am child process!\n");
                sleep(10);
                return 0;
        }
        else{
                printf("send signal to child process (%d)\n",pid);
                sleep(1);
                kill(pid, SIGABRT);
                wait(&status);
                if(WIFSIGNALED(status))
                        printf("child process receive signal %d\n", WTERMSIG(status));
        }
        return 0;
}

send signal to child process (25443)
Hi I am child process!
child process receive signal 6

sigprocmask(查询或设置信号遮罩)

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

sigprocmask()可以用来改变目前的信号遮罩,其操作依参数how来决定:
SIG_BLOCK 新的信号遮罩由目前的信号遮罩和参数set指定的信号遮罩作联集
SIG_UNBLOCK 将目前的信号遮罩删除掉参数set指定的信号遮罩
SIG_SETMASK 将目前的信号遮罩设成参数set指定的信号遮罩
如果参数set是NULL,how没有意义,线程的信号遮罩不变,可以用来获得当前的信号遮罩。如果参数oldset不是NULL指针,那么目前的信号遮罩会由此指针返回。
多线程中应使用pthread_sigmask。

执行成功则返回0,如果有错误则返回-1。
EFAULT 参数set,oldset指针地址无法存取
EINTR 此调用被中断

sigpending(查询被搁置的信号)

#include <signal.h>
int sigpending(sigset_t *set);

sigpending()会将被搁置的信号集合由参数set指针返回。
执行成功则返回0,如果有错误则返回-1。

EFAULT 参数set指针地址无法存取
EINTR 此调用被中断

sigaction(查询或设置信号处理方式)

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

sigaction()会依参数signum指定的信号编号来设置该信号的处理函数。参数signum可以指定SIGKILL和SIGSTOP以外的信号。
参数结构sigaction至少包含以下成员:
void (*sa_handler)(int);//pointer to a signal-catching function, or one of the macros SIG_IGN or SIG_DFL.
sigset_t sa_mask;//在执行信号处理函数时阻塞的信号集
int sa_flags;
void (sa_sigaction)(int,siginfo_t,void*);//pointer to a signal-catching function.

如果SA_SIGINFO在sa_flags中清空,将使用sa_handler作为信号处理函数;如果SA_SIGINFO在sa_flags中置位,将使用sa_sigaction作为信号处理函数。
sa_flags用来设置信号处理的其他相关操作,可以是以下数值的OR 运算组合:
SA_NOCLDSTOP:如果参数signum为SIGCHLD,则当子进程暂停时并不会通知父进程
SA_RESETHAND/SA_ONESHOT:当调用新的信号处理函数前,将此信号处理方式改为系统预设的方式
SA_NODEFER/SA_NOMASK:在处理此信号未结束前不理会此信号的再次到来
如果参数oldact不是NULL指针,则原来的信号处理方式会由此结构sigaction返回。
如果参数act是NULL指针,信号处理方式不会发生改变。

执行成功则返回0,如果有错误则返回-1。
EINVAL 参数signum不合法
EFAULT 参数act,oldact指针地址无法存取
EINTR 此调用被中断

sigset_t

/* A `sigset_t' has a bit for each signal.  */

# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
  {
    unsigned long int __val[_SIGSET_NWORDS];
  } __sigset_t;
#endif

typedef __sigset_t sigset_t;
#include <signal.h>
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigismember(const sigset_t *set, int signum);

sigaddset()用来将参数signum代表的信号加入至参数set信号集里。
sigdelset()用来将参数signum代表的信号从参数set信号集里删除。
sigemptyset()用来将参数set信号集初始化并清空。
sigfillset()用来将参数set信号集初始化,然后把所有的信号加入到此信号集里。
以上四个函数执行成功则返回0,如果有错误则返回-1。
sigismember()用来测试参数signum代表的信号是否已加入至参数set信号集里。信号集已有该信号则返回1,没有则返回0。如果有错误则返回-1。

错误代码
EFAULT 参数set指针地址无法存取
EINVAL 参数signum非合法的信号编号


popen(建立管道I/O)

#include <stdio.h>
FILE *popen(const char *command, const char *type);

popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。参数type可使用“r”代表读取,“w”代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。此外,所有使用文件指针(FILE*)操作的函数也都可以使用,除了fclose()以外。

若成功则返回文件指针,否则返回NULL,错误原因存于errno中。
EINVAL 参数type不合法

pclose(关闭管道I/O)

#include <stdio.h>
int pclose(FILE *stream);

pclose()用来关闭由popen所建立的管道及文件指针。参数stream为先前由popen()所返回的文件指针。

返回子进程的结束状态。如果有错误则返回-1,错误原因存于errno中。
ECHILD pclose()无法取得子进程的结束状态

#include <stdio.h>
main()
{
    FILE *fp;
    char buffer[80];
    fp=popen("cat /etc/passwd","r");
    fgets(buffer,sizeof(buffer),fp);
    puts(buffer);
    pclose(fp);
}

root:x:0:0:root:/root:/bin/bash

pipe(建立管道)

#include <unistd.h>
int pipe(int filedes[2]);

pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,filedes[1]则为管道的写入端。

若成功则返回零,否则返回-1,错误原因存于errno中。
EMFILE 进程已用完文件描述词最大量
ENFILE 系统已无文件描述词可用
EFAULT 参数filedes数组地址不合法

/*父进程借管道将字符串"hello!\n"传给子进程并显示*/
#include <unistd.h>
main()
{
int filedes[2];
char buffer[80];
pipe(filedes);
if(fork()>0){
char s[] = "hello!\n";
write(filedes[1],s,sizeof(s));
}
else{
read(filedes[0],buffer,80);
printf("%s",buffer);
}
}

hello!

mkfifo(建立具名管道)

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);

mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode-umask)。mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开FIFO文件时,O_NONBLOCK旗标会有影响:
1、当使用O_NONBLOCK旗标时,打开FIFO文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO文件来读取,则写入的操作会返回ENXIO 错误代码。
2、没有使用O_NONBLOCK旗标时,打开FIFO来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样的,打开FIFO文件来写入的操作会等到其他进程打开FIFO文件来读取后才正常返回。

若成功则返回0,否则返回-1,错误原因存于errno中。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FIFO "/tmp/fifo.fifo"
main()
{
        char buffer[80];
        int fd;
        unlink(FIFO);
        mkfifo(FIFO, 0666);
        if(fork()>0){
                char s[] = "hello!";
                fd = open(FIFO,O_WRONLY);
                write(fd,s,sizeof(s));
                close(fd);
        }
        else{
                fd = open(FIFO,O_RDONLY);
                read(fd,buffer,80);
                puts(buffer);
                close(fd);
        }
}

hello!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值