0805|IO进程线程day8 IPC机制(进程间通信机制)管道+信号

本文介绍了Linux系统中IPC(进程间通信)机制,包括管道和信号。管道分为无名管道和有名管道,阐述了其原理、特性及操作方法,并给出相关代码示例。信号部分介绍了概念、处理方式、常见信号及相关函数,如signal、kill、alarm等,还说明了用信号回收僵尸进程的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是IPC机制

概念:        

        IPC机制:Inter Process Communication,即进程间通信机制

        进程与进程间的用户空间相互独立,内核空间共享。所以如果要实现进程间的通信,需要使用进程间通信机制。

分类(3类):

  1. 传统的进程间通信机制
        无名管道  pipe
        有名管道  fifo
        信号      signal
  2. system v操作系统的IPC对象
        消息队列  message queue
        共享内存  shared memory
        信号灯集  semaphore
  3. 可用于跨主机传输的通信
        套接字  socket

二、管道

2.1 管道的原理

        在进程的3~4G内核空间中,创建一个管道(特殊的文件),管道中的数据是直接存储在内存中的。

2.2 管道的特性

1) 管道可以看成是一个特殊的文件一般的文件存放在磁盘上,而管道中的内容存储在内存中

2) 管道遵循先进先出的原则。(队列形式实现);

3) 管道的大小64K = 64*1024 = 65536bytes ;

4) 对于管道的读操作是一次性,如果对管道进行读操作,那么被读取的数据会从管道中删除 ;

5) 管道是一种半双工的通信方式 :

单工:只能A发消息给B,B无法发消息给A;
半双工:同一时间,只能A发消息给B,或者B发消息给A;
全双工:同一时间,可以双方通信。

6) 当管道的读写端均被关闭的时候,此时会释放管道在内核内存中的空间 ;

7) 从管道中读取数据

         · 当管道的读写端均存在
           ① 管道中没有数据的时候读函数阻塞
           ② 管道中实际拥有的个数a(10个),大于要读取的数据个数b(5个),则实际读取b(5个);
           ③ 若管道中有5个数据,读取10个,实际读5个
         · 当管道的写端不存在(父子进程的写端均关闭)
           ① 此时去读取数据,若管道中原来存在数据,则先将数据读取完毕,
           ② 若没有数据了,read函数不阻塞,且read函数立即返回0;

8) 向管道中写入数据

         · 当管道的读写端均存在
           ① 管道写满后write函数会阻塞。

        · 当管道的写端不存在(父子进程的写端均关闭)
           ① 此时只要尝试向管道中写入数据(只要调用了write函数),调用write函数的进程会收到一个管道破裂信号,该信号会导致当前进程退出
           ② 管道破裂信号:SIGPIPE

2.3 无名管道(pipe)

1) 无名管道的特点

  1. 无名管道:顾名思义即没有名字的管道文件,在用户空间不可见的管道文件
  2. 无名管道只能用于具有亲缘关系的进程间通信
  3. 由于无名管道存在于内核空间中,所以我们需要直接对内核进行操作,此时只能使用系统调用函数,即只能使用文件IO函数,例如:open read write close 。 但是不能使用lseek函数。

无名管道只能用于具有亲缘关系的进程间通信,为什么?

  1. 无名管道在文件系统中不可见,所以无亲缘关系的进程无法拿到同一根管道的读写端。
  2. 子进程会克隆父进程的文件描述符表,所以可以在父进程中创建一根管道,然后fork一份资源给子进程,此时子进程可以拿到与父进程相同的文件描述符表。即可以拿到同一根无名管道的读写端。

2) pipe

功能:创建一个无名管道,同时打开无名管道的读写端;

原型:

       #include <unistd.h>

       int pipe(int pipefd[2]); int* pfd;  int pfd[]

参数:

    int pipefd[2]:函数运行完毕后,该参数指向的数组中会存储两个文件描述符;
        pipefd[0]: 读端文件描述符;
        pipefd[1]: 写端文件描述符;

返回值:

        成功,返回0;

        失败,返回-1,更新errno;

2.4 有名管道(fifo)

1) 有名管道的特点

  1. 有名管道:顾名思义即有名字的管道文件,在用户空间可见的管道文件
  2. 有名管道能用于任意的进程间通信,因为在文件系统中可见
  3. 由于有名管道存在于内核空间中,所以我们需要直接对内核进行操作,此时只能使用系统调用函数,即只能使用文件IO函数,例如:open read write close 。但是不能使用lseek函数。

2) 创建有名管道文件

① 用shell指令
    mkfifo 有名管道名字
    mkfifo myfifo
② 用mkfifo函数创建

功能:创建一根有名管道;

原型:

       #include <sys/types.h>
       #include <sys/stat.h>

       int mkfifo(const char *pathname, mode_t mode);

参数:

    char *pathname:指定要创建的有名管道的路径以及名字;
    mode_t mode:   有名管道的权限:0664 0777,真实的权限 (mode & ~umask)
                    the  permissions of the created file are (mode & ~umask)

返回值:

        成功,返回0;

        失败,返回-1,更新errno;

        errno == 17,文件已经存在的错误,这是一个允许存在的错误,忽略该错误

练习:创建一根有名管道
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
    //创建一根管道
    if(mkfifo("./fifo",0664) < 0)
    {
        if(errno != 17)
        {
            perror("mkfifo");
            return -1;
        }
    }
    printf("mkfifo success\n");

    return 0;
}                                         
                                          

3) 操作有名管道文件

  • 操作有名管道与用文件IO操作普通文件一致.
  • open read write close函数操作有名管道即可

功能:open函数功能是打开一个文件;

原型:

       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

       int open(const char *pathname, int flags);

参数:

    int flags:
       O_RDONLY  只读
       O_WRONLY  只写
       O_RDWR    读写
    ---上述三种必须,且只能包含一种---
       O_NONBLOCK     非阻塞

1) int flags == O_RDONLY

  • open函数阻塞,此时需要另外一个进程或线程以写的方式打开同一根管道,open函数解除阻塞。

2) int flags == O_WRONLY

  • open函数阻塞,此时需要另外一个进程或线程以读的方式打开同一根管道,open函数解除阻塞。

3) int flags == O_RDWR

  • open函数不阻塞,此时管道的读写端均被打开。

        当管道的读写端均被打开的时候,此时open函数不阻塞。

4) int flags == O_RDONLY | O_NONBLOCK

  • open函数不阻塞,open函数运行成功,此时管道只有读端。

5) int flags == O_WRONLY | O_NONBLOCK

  • open函数不阻塞,open函数运行失败,此时管道的读写端均打开失败;
读端
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    umask(0);

    if(mkfifo("./fifo", 0777) < 0)
    {
        //printf("errno = %d\n", errno);
        if(errno != 17)     //17 == EEXIST
        {
            perror("mkfifo");
            return -1;
        }
    }
    printf("create FIFO success\n");

    //open函数阻塞
    int fd = open("./fifo", O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return -1;
    }
    printf("open FIFO rdonly success  fd=%d\n", fd);

    char buf[128] = "";
    ssize_t res = 0;
    while(1)
    {
        bzero(buf, sizeof(buf));
        res = read(fd, buf, sizeof(buf));
        if(res < 0)
        {
            perror("read");
            return -1;                                  
        }
        else if(0 == res)
        {
            printf("对端关闭\n");
            break;
        }

        printf("%ld :%s\n", res, buf);
    }

    close(fd);

    return 0;
}
写端
#include <stdio.h>                                    
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    umask(0);

    if(mkfifo("./fifo", 0777) < 0)
    {   
        //printf("errno = %d\n", errno);
        if(errno != 17)     //17 == EEXIST
        {
            perror("mkfifo");
            return -1; 
        }
    }   
    printf("create FIFO success\n");

    //open函数阻塞
    int fd = open("./fifo", O_WRONLY);
    if(fd < 0)
    {   
        perror("open");
        return -1; 
    }   
    printf("open FIFO wronly success  fd=%d\n", fd);

    char buf[128] = ""; 
    while(1)
    {   
        printf("请输入>>>");
        fgets(buf, sizeof(buf), stdin);
        buf[strlen(buf)-1] = 0;

        if(write(fd, buf, sizeof(buf)) < 0)
        {
            perror("write");
            return -1; 
        }
        printf("写入成功\n");
    }   

    close(fd);

    return 0;
}

练习:(半双工)打开两个终端,要求实现AB进程对话【两根管道】

 打开两个终端,要求实现AB进程对话

  1. A进程先发送一句话给B进程,B进程接收后打印
  2. B进程再回复一句话给A进程,A进程接收后打印
  3. 重复1.2步骤,当收到quit后,要结束AB进程
  • 提示:两根管道

A终端代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

/***************************A终端***************************/

int main(int argc, const char *argv[])
{
	//创建管道1    A终端写入--->管道1--->B终端读取
	if(mkfifo("./fifo",0664) < 0)
	{
		if(errno != 17)//如果错误是已有管道,则跳过,可正常运行
		{
			perror("mkfifo");
			return -1;
		}
	}
	printf("mkfifo pipe1 success __%d__\n",__LINE__);

	//创建管道2    B终端写入--->管道2--->A终端读取
	if(mkfifo("./myfifo",0664) < 0)
	{
		if(errno != 17)
		{
			perror("mkfifo");
			return -1;
		}
	}
	printf("mkfifo pipe2 success __%d__\n",__LINE__);

	//以写的方式打开管道1
	int fd_w=open("./fifo",O_WRONLY);
	if(fd_w < 0)
	{
		perror("open");
		return -1;
	}
	printf("open pipeA success __%d__\n",__LINE__);
	//以读的方式打开管道B
	int fd_r=open("./myfifo",O_RDONLY);
	if(fd_r < 0)
	{
		perror("open");
		return -1;
	}
	printf("open pipeB success __%d__\n",__LINE__);


	char buf[128]="";
	ssize_t res = 0;
	int c=-1;
	while(1)
	{
		//管道1操作(写入数据)
		printf("请输入要对B说的话>>> ");
		fgets(buf,sizeof(buf),stdin);    //从终端获取数据

		buf[strlen(buf)-1] = '\0';   //将\n改成\0
		if((write(fd_w,buf,sizeof(buf))) < 0)  //将字符串写进管道A  
		{
			perror("write");
			return -1;
		}
		//当管道1的读段关闭,管道1的写段尝试写入数据,则管道破裂,退出进程



		//管道2操作(读取数据)
		bzero(buf,sizeof(buf));//清空字符串
		res=read(fd_r,buf,sizeof(buf));//读取B管道中的数据
		
		c=strcmp(buf,"quit");//将读到的数据与quit比较
		if(0 == c)//如果相同,c为0,达到退出条件,可以退出循环
		{
			break;
		}
		//printf("写入数据成功 res=%ld\n",res);

		if(res < 0)//read函数执行失败,返回负数
		{
			perror("read");
			return -1;
		}   

		if(0 == res)//read执行成功,但读到了0个数据`
		{
			printf("对方进程退出\n");
			break;
		}
		//打印从管道2中读取到的数据
		printf("B:%s\n",buf);
	}
	
	//关闭管道1、管道2
	close(fd_r);
	close(fd_w);
	return 0;
}

B终端代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

/***************************B终端***************************/  

int main(int argc, const char *argv[])
{
	//创建管道1   A终端写入--->管道1--->B终端读取
	if(mkfifo("./fifo",0664) < 0)
	{
		if(errno != 17)
		{
			perror("mkfifo");
			return -1;
		}
	}
	printf("mkfifo pipe1 success __%d__\n",__LINE__);

	//创建管道2   B终端写入--->管道2--->A终端读取
	if(mkfifo("./myfifo",0664) < 0)
	{
		if(errno != 17)
		{
			perror("mkfifo");
			return -1;
		}
	}
	printf("mkfifo pipe2 success __%d__\n",__LINE__);
	
	//以读的方式打开管道1
	int fd_r=open("./fifo",O_RDONLY);
	if(fd_r < 0)
	{
		perror("open");
		return -1;
	}
	printf("open pipe1 success __%d__\n",__LINE__);
	//以写的方式打开管道2
	int fd_w=open("./myfifo",O_WRONLY);
	if(fd_w < 0)
	{
		perror("open");
		return -1;
	}
	printf("open pipe2 success __%d__\n",__LINE__);

	char buf[128]="";
	ssize_t res = 0;
	int c=-1;
	while(1)
	{
		//管道1操作(读取数据)
		bzero(buf,sizeof(buf));
		res=read(fd_r,buf,sizeof(buf));

		c=strcmp(buf,"quit");//判断B终端输入的是否是quit
		if(0 == c)
		{
			break;//是quit则退出进程
		}
		if(res < 0)
		{
			perror("read");
			return -1;
		}
		if(0 == res )
		{
			printf("对方进程退出\n");
			break;
		}
		printf("A:%s\n",buf);

		//管道2操作(写入数据)
		printf("请输入>>> ");
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf)-1] = '\0';
		if((write(fd_w,buf,sizeof(buf))) < 0)
		{
			perror("write");
			return -1;
		}
		//当管道2关闭,管道2的写段尝试写入数据,则管道破裂,退出进程
	}

	close(fd_r);
	close(fd_w);
	return 0;
}

A终端结果

ubuntu@ubuntu:02_fifo$ gcc 03_pipe_w.c -o w
ubuntu@ubuntu:02_fifo$ ./w
mkfifo pipe1 success __22__
mkfifo pipe2 success __33__
open pipeA success __42__
open pipeB success __50__
请输入要对B说的话>>> 你好,我是A
B:你好呀,我是B
请输入要对B说的话>>> 你吃饭了吗?
B:吃了,你呢
请输入要对B说的话>>> 不告诉你
ubuntu@ubuntu:02_fifo$ 

B终端结果

ubuntu@ubuntu:02_fifo$ gcc 02_pipe_r.c -o r
ubuntu@ubuntu:02_fifo$ ./r
mkfifo pipe1 success __22__
mkfifo pipe2 success __33__
open pipe1 success __42__
open pipe2 success __50__
A:你好,我是A
请输入>>> 你好呀,我是B
A:你吃饭了吗?
请输入>>> 吃了,你呢
A:不告诉你
请输入>>> quit
对方进程退出
ubuntu@ubuntu:02_fifo$ 

fd741777d8ed4957bfa812ba1a3af75e.png

附加题:(全双工)A能随时发信息给B,B能随时接收A发送的数据,反之亦然。

三、信号

3.1 信号的概念

1) 原理

① 信号是软件层次上,对中断的一种模拟

  • 中断:暂停当前的任务,先去执行其他任务

②信号是一种异步通信方式,AB进程各自运行各自的

  • 同步:多个任务之间有先后关系,必须把任务A结束后,才能执行任务B;
  • 异步:多个任务之间没有关系,各自运行各自的任务,通过CPU调度各个任务。

2) 进程对信号的处理方式【重点】 

① 执行默认操作\执行缺省操作

  • 每个信号都有自己默认的处理函数,当信号发生的时候,执行信号对应的默认处理函数。

② 忽略信号

  • 对信号不做处理,但是有两个信号不能忽略 9) SIGKILL 19) SIGSTOP

③ 捕获信号

  • 修改信号的默认处理函数为自定义处理函数,当信号发生的时候,执行自定义处理函数。
  • 9) SIGKILL 19) SIGSTOP,无法捕获。

3)常见的信号

kill     -l     查看所有信号     62个信号,其中32 33没有

 1) SIGHUP             2) SIGINT             3) SIGQUIT            4) SIGILL                 5) SIGTRAP
 6) SIGABRT            7) SIGBUS             8) SIGFPE             9) SIGKILL                10) SIGUSR1
11) SIGSEGV            12) SIGUSR2           13) SIGPIPE           14) SIGALRM                15) SIGTERM
16) SIGSTKFLT          17) SIGCHLD           18) SIGCONT           19) SIGSTOP                20) SIGTSTP
21) SIGTTIN            22) SIGTTOU           23) SIGURG            24) SIGXCPU                25) SIGXFSZ
26) SIGVTALRM          27) SIGPROF           28) SIGWINCH          29) SIGIO                30) SIGPWR
31) SIGSYS             34) SIGRTMIN          35) SIGRTMIN+1        36) SIGRTMIN+2            37) SIGRTMIN+3
38) SIGRTMIN+4         39) SIGRTMIN+5        40) SIGRTMIN+6        41) SIGRTMIN+7            42) SIGRTMIN+8
43) SIGRTMIN+9         44) SIGRTMIN+10       45) SIGRTMIN+11       46) SIGRTMIN+12            47) SIGRTMIN+13
48) SIGRTMIN+14        49) SIGRTMIN+15       50) SIGRTMAX-14       51) SIGRTMAX-13            52) SIGRTMAX-12
53) SIGRTMAX-11        54) SIGRTMAX-10       55) SIGRTMAX-9        56) SIGRTMAX-8            57) SIGRTMAX-7
58) SIGRTMAX-6         59) SIGRTMAX-5        60) SIGRTMAX-4        61) SIGRTMAX-3            62) SIGRTMAX-2
63) SIGRTMAX-1         64) SIGRTMAX    

① 硬件能按出来的信号

  • 2) SIGINT       默认处理函数:退出进程 ctrl + c
  • 3) SIGQUIT    默认处理函数:退出进程 ctrl + \
  • 20) SIGTSTP  默认处理函数:挂起进程 ctrl + z 此时进程没有结束

② 无法被忽略、捕获的信号

  • 9) SIGKILL      默认处理函数:退出进程 kill -9 pid
  • 19) SIGSTOP  默认处理函数:退出进程

③ 常见的信号

  • 11) SIGSEGV  段错误信息,默认处理函数:退出进程
  • 13) SIGPIPE   管道破裂信号,默认处理函数:退出进程
  • 14) SIGALRM 时钟信号,默认处理函数:退出进程
  • 17) SIGCHLD 当子进程退出后,父进程会收到17号信号。默认处理函数不会导致进程退出。

3.2 信号的相关函数

1) signal

功能:捕获信号,为信号注册新的处理函数;

原型:

       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);     //void (*handler)(int);

参数:

    int signum:指定要捕获的信号对应的编号。可以填编号,也可以填对应的宏。2) SIGINT
    sighandler_t handler:函数指针,回调函数;
        1) SIG_IGN:忽略信号;     9) 19)号信号无法忽略;
        2) SIG_DFL:执行默认操作;
        3) 传入一个函数的首地址,代表捕获信号,且该函数的返回值必须是void类型,参数列表必须是int类型,
        例如:void handler(int sig)
        {    
                                
        }
typedef void (*sighandler_t)(int);     typedef void (*)(int)   sighandler_t; 
 
 typedef 旧的类型名  新的类型名;
 typedef int uint32_t;                     int a ----> uint32_t a;
 typedef int*    pint;                     int* pa ---> pint pa;
 typedef void (*)(int)   sighandler_t;     void (*ptr)(int) ----> sighandler_t ptr

返回值:

        成功,返回该信号的上一个信号处理函数的首地址; 默认处理函数的首地址获取不到,返回NULL;

        失败,返回SIG_ERR ((__sighandler_t)-1),更新errno;

注意:

        当在某个信号A的信号处理函数中时,再次触发信号A,此时信号A的处理函数不会再次被载入运行,即第二次触发的信号A被屏蔽。但是此时若触发了信号B,信号B的处理函数是可以正常被载入的,即没有屏蔽信号B;

练习1:捕获一个信号

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

void handler(int sig)
{
    printf("__%d__\n",__LINE__);
    while(1)
    {
        sleep(1);
        printf("this is sig=%d\n",sig);
    }
    return;
}

int main(int argc, const char *argv[])       
{
    //捕获2)SIGINT信号 ctrl + c
    if(signal(2, handler) == SIG_ERR)
    {
        perror("signal");
        return -1;
    }
    printf("捕获2号信号成功\n");

    while(1)
    {
        printf("this is main func\n");
        sleep(1);
    }
    return 0;
}

练习2:捕获2、3、20号信号

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

void handler(int sig)
{
    printf("this is sig=%d\n",sig);
    return;
}

int main(int argc, const char *argv[])
{

    //捕获2)SIGINT信号 ctrl + c
    if(signal(2, handler) == SIG_ERR)
    {
        perror("signal");
        return -1;
    }
    printf("捕获2号信号成功\n");

    //捕获3)SIGQUIT信号 ctrl + \

    if(signal(3, handler) == SIG_ERR)
    {
        perror("signal");
        return -1;
    }
    printf("捕获3号信号成功\n");

    //捕获20)SIGTSTP信号 ctrl + z
    if(signal(20, handler) == SIG_ERR)     
    {
        perror("signal");
        return -1;
    }
    printf("捕获20号信号成功\n");

    while(1)
    {
        printf("this is main func\n");
        sleep(1);
    }
    return 0;
}

2)用信号的方式回收僵尸进程【重点】

① 子进程退出后,父进程会收到17)SIGCHLD信号。

② 父进程中捕获17)SIGCHLD信号,给该信号注册新的处理函数。在该新的处理函数中执行waitpid函数,回收僵尸进程。

③ 当在信号A的处理函数内部时,再次触发A信号,会导致信号屏蔽,会造成多个子进程短时间内同时退出,父进程只会处理一个17号信号,导致僵尸进程收不干净的问题。

④ 解决方式:当成功回收到僵尸进程后,再回收一次。直到没有僵尸进程,结束循环。即判断waitpid(-1, NULL, WNOHANG);的返回值

        =0,有子进程,但是没有僵尸进程

        =-1,没有子进程,也没有僵尸进程

练习:回收僵尸进程(2种方法):
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>

int count=0;

//方法一:
void callBack(int sig)
{
    while(1)
    {
        //1当回收成功后,再收一次,直到回收失败
        //-1, 没有僵尸进程,也没有子进程
        //=0,没有僵尸进程,但是有子进程
        pid_t wpid = waitpid(-1,NULL,WNOHANG);
        if(wpid <= 0)
            break;
        printf("[%d] wpid = %d\n",++count,wpid);
    }
    return;
}
/*方法二:
void callBack(int sig)
{
    while(waitpid(-1,NULL,WNOHANG)>0);
    return;
}
*/
int main(int argc, const char *argv[])
{                                                            
    //捕获17号信号
    if(signal(SIGCHLD,callBack) == SIG_ERR)
    {
        perror("signal");
        return -1;
    }
    printf("17号信号捕捉成功\n");
    int i=0;
    while(i<100)
    {
        if(fork()==0) //若是子进程
        {
            exit(0);  //退出
        }
        i++;          //只有父进程会++
    }

    //能运行到这个位置,代表是父进程
    while(1)
        sleep(1);
    return 0;
}

3) kill

功能:给指定进程或者进程组发送一个信号;

原型:

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

       int kill(pid_t pid, int sig);

参数:

        pid_t pid指定要发送的进程或者进程组;

  • pid > 0,  将信号发送给指定的进程,进程号==pid参数;
  • pid == 0, 将信号发送给当前进程组下的所有进程;
  • pid == -1, 将信号发送给当前进程权限所能送达的所有进程,除了1号进程;
  • pid < -1,  将信号发送给指定进程组下的所有进程。进程组ID == -pid参数;

        int sig指定要发送的信号的编号,可以填对应的宏;

  • sig==0代表没有信号被发送,但是依然会检测对方进程是否存在,或者是否有权限访问。

       

返回值:

        成功,返回0;

        失败,返回-1,更新errno;

4) alarm

功能:设置一个定时器,当时间到后,给当前进程发送一个14) SIGALRM 信号

原型:

       #include <unistd.h>

       unsigned int alarm(unsigned int seconds);

参数:

        unsigned int seconds

                设置定时器时间,以秒为单位; seconds == 0, 则取消定时器;

       

返回值:

        >0, 返回上一个定时器没有走完的时间;

         =0, 没有未走完的定时器;

练习:设置一个定时器

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值