Linux系统信号管理相关操作函数
来源:互联网 发布:淘宝企业店铺所需资料 编辑:程序博客网 时间:2024/05/17 04:28
Unix信号管理
信号(signal)
Unix系统中,用信号实现软件中断;
Ctrl+C ->SIGINT
段错误 ->SIGSEGV
总线错误 ->SIGBUS
浮点数例外 ->SIGFPE
终端关闭 ->SIGHUP
定时到期 ->SIGALARM
Ctrl+\ ->SIGQUIT不同于信号2,会产生core dump文件;
中断的概念
中断(interrupt)是程序中止(暂停)现在的代码,转而执行其他的代码;
中断分为软件中断和硬件中断;软件中断就是用软件的方式中断程序,硬件中断就是硬件出故障导致程序中断;
软件中断的主要方式就是信号;
信号的本质是非负整数;每个信号都有一个宏名称,都以SIG开头,比如信号2是SIGINT宏;
用命令kill可以查看/发送信号;
kill -9 pid 给进程发信号9,用于结束进程;
kill -l 字母l(list),可以查看所有的信号;
关于0做除数
整数除以0会引发浮点数例外FPE,终止程序;
浮点除以0会得到结果,结果是无穷大;
Unix信号和Linux信号不同,linux:0-64,中间不连续;Unix:0-48,此外,有些信号对应的值也不相同;因此编程时尽量使用信号的宏名称,而不要用数值;
信号是异步处理方式;无法判断信号什么时候会来,因此就无法知道什么时候处理信号;
信号0有特殊用途,本身不代表任何的事件,也不会处理;用于测试是否有权限发信号;
kill -0 1
进程之间可以互相发信号,但受到用户权限的影响;用户只能给自己的进程发信号,不能给其他用户的进程发信号;root可以给所有进程发信号;
硬件故障和函数调用都可能产生信号;
信号的分类
不可靠信号//这种信号不支持排队,因此有可能丢失,是非实时信号;
//1-31都是不可靠信号;
可靠信号//支持排队,因此不会丢失,是实时信号;
//34-64都是可靠信号;
程序收到信号以后的处理方式
1-> 默认处理方式,80%的默认处理方式是退出进程;
2-> 忽略信号,不做任何处理;
3-> 程序员可以自定义信号的处理方式,只需要写一个信号处理函数;
信号9不能被忽略,也不能自定义;
信号处理的实现步骤
1-> 写一个信号处理函数;
2-> 用signal()/sigaction()注册信号处理方式;
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler函数指针);
将信号与处理方式绑定在一起;
第2个参数为函数指针 void (*fa)(int),函数为void类型,参数为int;
函数返回函数指针格式,即返回函数;
失败返回SIG_ERR;
当signal(信号, 函数指针)执行完毕后,只要有信号来,系统就会调用函数指针所对应的函数;
第2个参数决定了信号的处理方式,可以是
SIG_IGN 忽略;
SIG_DFL 默认处理(一般都是恢复成默认);
函数指针 自定义函数的处理方式;
子进程的信号处理
如果创建了子进程,
fork()创建的子进程完全沿袭父进程的信号处理方式,
vfork()+execl()创建的子进程,父进程默认子进程也默认,父进程忽略子进程也忽略,父进程自定义处理函数子进程默认;
原因是vfork()+execl()创建的子进程代码区没有父进程的处理函数;
忽略和默认的宏所有的进程都可以共享,所以能够继承;
killall a.out 可以结束所有的a.out进程;
发信号的方法
1.键盘发送信号(部分信号);
Ctrl+C 发送信号2,SIGINT;
Ctrl+\ 发送信号3,SIG_QUIT;
2.出错(部分信号);
整数除以0 信号8,SIGFPE;
段错误 信号11,SIGSEGV;
总线错误 信号7,SIGBUS;
3.kill命令发送(全部信号);格式:
kill -信号 进程PID
4.信号发送函数
raise() 给本进程发任意信号;
kill() 给任意进程(或进程组)发任意信号;
alarm() 给本进程发特定信号(闹钟);
sigqueue() 给任意进程发任意信号,可以附带额外的数据(少用);
主讲kill()函数,了解alarm();
int kill(pid_t pid, int signo);
参数
pid指定发给哪个/哪些进程;
signo就是发送哪个信号;
pid有4种值
正数 给进程ID=pid的特定进程发信号;
-1 给所有有权限的进程发信号;
0 给本进程组的进程发信号;
<-1 给进程组ID=-pid的进程发信号;
unsigned int alarm(unsigned int seconds);
seconds秒之后产生一个闹钟信号,SIGALRM;不会产生第2个;
如果seonds为0,将不会有新的闹钟被注册,意味着取消所有闹钟;
如果之前已经注册过alarm()但还未到时,将被取消;
如果当前没有正在运行的闹钟,将返回0;
如果还有没结束的闹钟,将返回前面的闹钟剩余的秒数;
可以用来做一些计划任务;
unsigned int sleep(unsigned int seconds);
会使调用的线程休眠,直到seconds到时;或者被没有忽略的信号中断;
可能休眠seconds秒;也可能被非忽略的信号打断,并返回剩余秒数;
睡足seconds秒后返回0,被信号中断返回剩余秒数;
int usleep(useconds_t usec);
usleep()是微秒(microsecond)级的休眠函数;
成功返回0,失败返回-1;
microsecond微秒us
milisecond毫秒ms
如果用一个int类型表示一个信号有无似乎有些浪费资源,可以考虑只用一个二进制位来表示信号的有无;
long long int 是标c的64位整数;
32位的有符号整数大致范围在正负21亿;即0x80000000到0x7FFFFFFF之间;
32位的无符号整数大致范围在0到42亿;即0x00000000到0xFFFFFFFF之间;
做软件要考虑到扩展性,兼容性,健壮型,可移植性;
思考,如何存储一个50位的超大整数;
方法1,以字符串形式存放;3 + '0' = '3';
方法2,定义一个结构体,结构体里面分段存储;
信号集
信号集就是信号的集合,可以理解成一个超大的整数(为了操作系统的扩展性);
用一个二进制位对应一个信号(1代表有,0代表无);
最后一位代表信号1,如果最后一位是1代表信号集中有信号1,如果是0,就没有信号1;
信号集的类型 sigset_t;
使用sizeof关键字可以获得sigset_t类型的大小,实际是128字节的超大整数;
对比数据结构
数据结构中逻辑结构包括
1-> 集 元素之间没有任何关系,除了在一个集里面;
2-> 线性结构 元素之间是前后一对一的关系;
3-> 树形结构 元素之间是一对多的父子关系;
4-> 网状结构 元素之间是多对多的网格关系;
物理结构
线性和链表
运算结构
1-> 创建和删除;
2-> 增加元素和删除元素;
3-> 修改和查找;
4-> 排序和其他算法;
关于数据结构sigset_t,需要提供基本的函数如下
1-> 增加元素
sigaddset() 增加一个信号(将对应二进制位置1);
sigfillset() 放入所有信号(全部增加);
2-> 删除信号
sigdelset() 删除一个信号(将对应二进制位置0);
sigemptyset() 清空信号集(全部删除);
3-> 查找信号
sigismember() 判断信号是否存在信号集中;
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
成功返回0,失败返回-1;
int sigismember(const sigset_t *set, int signum);
存在返回1,不存在返回0,失败返回-1;
信号屏蔽
在执行一些关键代码时,进程需要屏蔽一些信号,防止信号中断关键任务;
信号屏蔽无法保证信号不来,但信号可以暂时不做处理,不会中断关键代码;等到关键代码执行完毕,解除信号屏蔽时再中断代码,返回执行信号处理的函数;
函数sigprocmask()负责信号屏蔽和解除信号屏蔽;
int sigprocmask(int how, const sigset_t *newset, sigset_t *oldset);
参数
newset 代表需要屏蔽的信号(集);//传入的参数
oldset 代表传出旧的信号屏蔽字(不用传出给NULL);//传出的参数;
how是运算的方式
SIG_BLOCK 旧的+新的,比如
abc + cde -> abcde
SIG_UNBLOCK 旧的-新的,比如
abc - cde -> ab
SIG_SETMASK 直接使用新的,不考虑旧的,比如
abc cde -> cde
注:how直接选择SIG_SETMASK即可;
sigset_t pend;
sigpending(&pend);可以取屏蔽期间哪些信号来过;
int sigpending(sigset_t *set);
可以将屏蔽期间捕获的信号存入set中;
成功返回0,失败返回-1;
信号(signal)
Unix系统中,用信号实现软件中断;
Ctrl+C ->SIGINT
段错误 ->SIGSEGV
总线错误 ->SIGBUS
浮点数例外 ->SIGFPE
终端关闭 ->SIGHUP
定时到期 ->SIGALARM
Ctrl+\ ->SIGQUIT不同于信号2,会产生core dump文件;
中断的概念
中断(interrupt)是程序中止(暂停)现在的代码,转而执行其他的代码;
中断分为软件中断和硬件中断;软件中断就是用软件的方式中断程序,硬件中断就是硬件出故障导致程序中断;
软件中断的主要方式就是信号;
信号的本质是非负整数;每个信号都有一个宏名称,都以SIG开头,比如信号2是SIGINT宏;
用命令kill可以查看/发送信号;
kill -9 pid 给进程发信号9,用于结束进程;
kill -l 字母l(list),可以查看所有的信号;
关于0做除数
整数除以0会引发浮点数例外FPE,终止程序;
浮点除以0会得到结果,结果是无穷大;
Unix信号和Linux信号不同,linux:0-64,中间不连续;Unix:0-48,此外,有些信号对应的值也不相同;因此编程时尽量使用信号的宏名称,而不要用数值;
信号是异步处理方式;无法判断信号什么时候会来,因此就无法知道什么时候处理信号;
信号0有特殊用途,本身不代表任何的事件,也不会处理;用于测试是否有权限发信号;
kill -0 1
进程之间可以互相发信号,但受到用户权限的影响;用户只能给自己的进程发信号,不能给其他用户的进程发信号;root可以给所有进程发信号;
硬件故障和函数调用都可能产生信号;
信号的分类
不可靠信号//这种信号不支持排队,因此有可能丢失,是非实时信号;
//1-31都是不可靠信号;
可靠信号//支持排队,因此不会丢失,是实时信号;
//34-64都是可靠信号;
程序收到信号以后的处理方式
1-> 默认处理方式,80%的默认处理方式是退出进程;
2-> 忽略信号,不做任何处理;
3-> 程序员可以自定义信号的处理方式,只需要写一个信号处理函数;
信号9不能被忽略,也不能自定义;
信号处理的实现步骤
1-> 写一个信号处理函数;
2-> 用signal()/sigaction()注册信号处理方式;
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler函数指针);
将信号与处理方式绑定在一起;
第2个参数为函数指针 void (*fa)(int),函数为void类型,参数为int;
函数返回函数指针格式,即返回函数;
失败返回SIG_ERR;
当signal(信号, 函数指针)执行完毕后,只要有信号来,系统就会调用函数指针所对应的函数;
第2个参数决定了信号的处理方式,可以是
SIG_IGN 忽略;
SIG_DFL 默认处理(一般都是恢复成默认);
函数指针 自定义函数的处理方式;
/* * signal()函数演示 * 再用命令kill发信号9和11试试 */#include <stdio.h>#include <signal.h>void func(int signo) { //signo就是信号 printf("捕获到信号%d\n", signo); signal(SIGINT, SIG_DFL); //恢复信号2默认处理方式 printf("信号2已恢复默认\n");}int main() { signal(SIGINT, func); //把信号2该成自定义func处理; signal(SIGQUIT, SIG_IGN); //把信号3改为忽略(Ctrl+\); signal(SIGKILL, func); //信号9只能默认,但不报错; //signal(SIGINT, SIG_DFL); printf("pid = %d\n", getpid()); while (1) ; return 0;}
子进程的信号处理
如果创建了子进程,
fork()创建的子进程完全沿袭父进程的信号处理方式,
vfork()+execl()创建的子进程,父进程默认子进程也默认,父进程忽略子进程也忽略,父进程自定义处理函数子进程默认;
原因是vfork()+execl()创建的子进程代码区没有父进程的处理函数;
忽略和默认的宏所有的进程都可以共享,所以能够继承;
/* * fork()与信号处理 */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>void fa(int signo) { printf("捕获了信号%d\n", signo);}int main() { if (signal(SIGINT, fa) == SIG_ERR) { //先设置再判断//信号2自定义 perror("signal 2"), exit(-1); } signal(SIGQUIT, SIG_IGN); //信号3忽略; pid_t pid = fork(); if (pid == 0) { /* 子进程执行分支 */ printf("chpid = %d\n", getpid()); while (1) ; /* 分别用kill给子进程发信号验证子进程信号的处理方式 */ exit(0); } printf("father pid = %d\n", getpid()); printf("father over\n"); return 0;}
/* * vfork()+execl()信号处理方式 */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>void fa(int signo) { printf("捕获了信号%d\n", signo);}/* 练习写代码验证vfork()+execl()子进程对信号的处理方式 */int main() { if (signal(SIGINT, fa) == SIG_ERR) { /* 先设置再判断//信号2自定义 */ perror("signal 2"), exit(-1); } signal(SIGQUIT, SIG_IGN); //信号3忽略; pid_t pid = vfork(); if (pid == 0) { /* 子进程执行分支 */ printf("chpid = %d\n", getpid()); /* 分别使用kill命令给子进程发信号验证处理方式 */ execl("./proc", "proc", NULL); /* * //proc.c * #include <stdio.h> * int main() { * printf("%d\n", getpid()); * while (1) ; * return 0; * } */ //while(1); exit(0); } printf("father over\n"); return 0;}
killall a.out 可以结束所有的a.out进程;
发信号的方法
1.键盘发送信号(部分信号);
Ctrl+C 发送信号2,SIGINT;
Ctrl+\ 发送信号3,SIG_QUIT;
2.出错(部分信号);
整数除以0 信号8,SIGFPE;
段错误 信号11,SIGSEGV;
总线错误 信号7,SIGBUS;
3.kill命令发送(全部信号);格式:
kill -信号 进程PID
4.信号发送函数
raise() 给本进程发任意信号;
kill() 给任意进程(或进程组)发任意信号;
alarm() 给本进程发特定信号(闹钟);
sigqueue() 给任意进程发任意信号,可以附带额外的数据(少用);
主讲kill()函数,了解alarm();
int kill(pid_t pid, int signo);
参数
pid指定发给哪个/哪些进程;
signo就是发送哪个信号;
pid有4种值
正数 给进程ID=pid的特定进程发信号;
-1 给所有有权限的进程发信号;
0 给本进程组的进程发信号;
<-1 给进程组ID=-pid的进程发信号;
/* * kill()函数练习 */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>void fa(int signo) { printf("进程%d捕获到了信号%d\n", getpid(), signo);}int main() { pid_t pid = fork(); if (pid == 0) { signal(SIGINT, fa); //子进程注册信号处理方式 while (1) ; } printf("父进程%d给子进程发信号\n", getpid()); sleep(1); kill(pid, SIGINT); return 0;}
unsigned int alarm(unsigned int seconds);
seconds秒之后产生一个闹钟信号,SIGALRM;不会产生第2个;
如果seonds为0,将不会有新的闹钟被注册,意味着取消所有闹钟;
如果之前已经注册过alarm()但还未到时,将被取消;
如果当前没有正在运行的闹钟,将返回0;
如果还有没结束的闹钟,将返回前面的闹钟剩余的秒数;
可以用来做一些计划任务;
/* * alarm()函数使用 */#include <stdio.h>#include <unistd.h>#include <signal.h>void fa(int signo) { printf("捕获了信号%d\n", signo);}int main() { signal(SIGALRM, fa); alarm(1); sleep(2); unsigned int res = alarm(5); //如果前面没有正在运行的闹钟,返回0; printf("res = %u\n", res); sleep(3); res = alarm(5); //返回之前闹钟的剩余秒数; printf("res = %u\n", res); sleep(1); res = alarm(5); //返回之前闹钟的剩余秒数; printf("res = %u\n", res); while (1) ; return 0;}
unsigned int sleep(unsigned int seconds);
会使调用的线程休眠,直到seconds到时;或者被没有忽略的信号中断;
可能休眠seconds秒;也可能被非忽略的信号打断,并返回剩余秒数;
睡足seconds秒后返回0,被信号中断返回剩余秒数;
int usleep(useconds_t usec);
usleep()是微秒(microsecond)级的休眠函数;
成功返回0,失败返回-1;
microsecond微秒us
milisecond毫秒ms
/* * sleep()函数演示 */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>void fa(int signo) { printf("捕获了信号%d\n", signo);}void print();int main() { signal(SIGINT, fa);//为了不让信号退出进程,方便看到sleep效果 printf("begin\n"); unsigned int res = sleep(10); //睡足返回0,被信号打断返回剩余秒数; /* sleep()会被未忽略的信号中断; */ printf("sleep() return value = %u\n", res); //返回剩余秒数 print(); printf("over\n"); return 0;}/* usleep()是微秒级的休眠;10的-6次方 */void print() { int i = 0; while (i++ <= 10) { printf("%d ", i); usleep(100000); //0.1s fflush(NULL); } printf("\n");}
如果用一个int类型表示一个信号有无似乎有些浪费资源,可以考虑只用一个二进制位来表示信号的有无;
long long int 是标c的64位整数;
32位的有符号整数大致范围在正负21亿;即0x80000000到0x7FFFFFFF之间;
32位的无符号整数大致范围在0到42亿;即0x00000000到0xFFFFFFFF之间;
做软件要考虑到扩展性,兼容性,健壮型,可移植性;
思考,如何存储一个50位的超大整数;
方法1,以字符串形式存放;3 + '0' = '3';
方法2,定义一个结构体,结构体里面分段存储;
信号集
信号集就是信号的集合,可以理解成一个超大的整数(为了操作系统的扩展性);
用一个二进制位对应一个信号(1代表有,0代表无);
最后一位代表信号1,如果最后一位是1代表信号集中有信号1,如果是0,就没有信号1;
信号集的类型 sigset_t;
使用sizeof关键字可以获得sigset_t类型的大小,实际是128字节的超大整数;
对比数据结构
数据结构中逻辑结构包括
1-> 集 元素之间没有任何关系,除了在一个集里面;
2-> 线性结构 元素之间是前后一对一的关系;
3-> 树形结构 元素之间是一对多的父子关系;
4-> 网状结构 元素之间是多对多的网格关系;
物理结构
线性和链表
运算结构
1-> 创建和删除;
2-> 增加元素和删除元素;
3-> 修改和查找;
4-> 排序和其他算法;
关于数据结构sigset_t,需要提供基本的函数如下
1-> 增加元素
sigaddset() 增加一个信号(将对应二进制位置1);
sigfillset() 放入所有信号(全部增加);
2-> 删除信号
sigdelset() 删除一个信号(将对应二进制位置0);
sigemptyset() 清空信号集(全部删除);
3-> 查找信号
sigismember() 判断信号是否存在信号集中;
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
成功返回0,失败返回-1;
int sigismember(const sigset_t *set, int signum);
存在返回1,不存在返回0,失败返回-1;
/* * 信号集练习 */#include <stdio.h>#include <signal.h>void print(const sigset_t *set, int size) { int i = size; char *p = (char *)set; printf("0x"); while (i-- > 0) { printf("%02x", p[i]); } printf("\n");}int main() { printf("set size = %d\n", sizeof(sigset_t)); //128 /* sigset_t的大小是128字节,可以容纳128*8个信号; */ sigset_t set; printf("清空前set: "); print(&set, sizeof(sigset_t)); /* 清空信号集 */ sigemptyset(&set); //清空set printf("清空后set: "); print(&set, sizeof(sigset_t)); /* 增加信号 */ sigaddset(&set, 1); //第1个bit置1 printf("放入1, set: "); print(&set, sizeof(sigset_t)); sigaddset(&set, 2); printf("放入2, set: "); print(&set, sizeof(sigset_t)); sigaddset(&set, 3); //第3个bit置1 printf("放入3, set: "); print(&set, sizeof(sigset_t)); sigaddset(&set, 7); /* printf("放入7, set = %d\n", set); */ printf("放入7, set: "); print(&set, sizeof(sigset_t)); /* 删除信号 */ sigdelset(&set, 3); //第3个bit清0 /* printf("删除3, set = %d\n", set); */ printf("删除3, set: "); print(&set, sizeof(sigset_t)); /* 查找信号 */ if (sigismember(&set, 2)) { printf("信号2在信号集中\n"); } else { printf("信号2不在信号集中\n"); } return 0;}
信号屏蔽
在执行一些关键代码时,进程需要屏蔽一些信号,防止信号中断关键任务;
信号屏蔽无法保证信号不来,但信号可以暂时不做处理,不会中断关键代码;等到关键代码执行完毕,解除信号屏蔽时再中断代码,返回执行信号处理的函数;
函数sigprocmask()负责信号屏蔽和解除信号屏蔽;
int sigprocmask(int how, const sigset_t *newset, sigset_t *oldset);
参数
newset 代表需要屏蔽的信号(集);//传入的参数
oldset 代表传出旧的信号屏蔽字(不用传出给NULL);//传出的参数;
how是运算的方式
SIG_BLOCK 旧的+新的,比如
abc + cde -> abcde
SIG_UNBLOCK 旧的-新的,比如
abc - cde -> ab
SIG_SETMASK 直接使用新的,不考虑旧的,比如
abc cde -> cde
注:how直接选择SIG_SETMASK即可;
sigset_t pend;
sigpending(&pend);可以取屏蔽期间哪些信号来过;
int sigpending(sigset_t *set);
可以将屏蔽期间捕获的信号存入set中;
成功返回0,失败返回-1;
/* * sigprocmask()信号屏蔽练习 */#include <stdio.h>#include <stdlib.h>#include <signal.h>void fa(int signo) { printf("捕获了信号%d\n", signo);}int main() { signal(SIGINT, fa); //不可靠信号不支持排队,屏蔽时丢失; signal(SIGQUIT, fa); //只能知道该信号来过; signal(50, fa); //可靠信号支持排队,屏蔽时不丢失; printf("pid = %d\n", getpid()); printf("执行普通程序,不屏蔽信号\n"); sleep(20); printf("++++++++++++++++++++++++\n"); printf("执行关键程序,屏蔽信号\n"); sigset_t new, old; sigemptyset(&new); sigaddset(&new, SIGINT); sigaddset(&new, SIGQUIT); sigaddset(&new, 50); //已准备号待屏蔽的信号 sigprocmask(SIG_SETMASK, &new, &old); //屏蔽 sleep(15); printf("关键代码执行完毕,将解除屏蔽\n"); sigset_t pend; sigpending(&pend); //解除屏蔽前取信号屏蔽期间哪些信号来过; printf("------------------------\n"); sigprocmask(SIG_SETMASK, &old, NULL); //解除屏蔽 printf("已解除屏蔽\n"); int i = 0; for (i = 1; i <= 63; i++) { /* if (sigismember(&pend, SIGINT)) { */ if (sigismember(&pend, i)) { printf("信号屏蔽期间,信号%d来过\n", i); } } sleep(10); return 0;}
0 0
- Linux系统信号管理相关操作函数
- Linux系统内存管理及相关操作函数
- Linux系统进程管理及相关操作函数
- linux作业管理相关信号
- linux系统编程之信号(五):信号集操作函数,信号阻塞与未决
- linux系统编程之信号(五):信号集操作函数,信号阻塞与未决
- linux信号集操作函数
- linux信号处理 --和信号相关的几个系统调用
- Linux信号简介和信号处理相关函数
- Linux信号简介和信号处理相关函数
- 内存管理相关函数 -- Linux
- linux 信号集操作函数,信号阻塞与未决
- LINUX系统服务相关操作
- Linux系统相关基础操作
- 信号与系统相关
- linux文件操作相关函数
- 嵌入式学习28(linux系统函数之文件、文件夹管理相关函数)
- linux系统编程之信号(六):信号发送函数sigqueue和信号安装函数sigaction
- hpu 1701 最后一个1 <水题>
- singleton的实现与销毁(1) --modern c++读书笔记
- 透明网关
- leetcode: (27) Remove Element
- HDU-2046 骨牌铺方格
- Linux系统信号管理相关操作函数
- 欧拉函数
- KVO 和 UIAlertViewController
- Linux服务管理/rpm的独立服务管理
- bmp(jpg)和avi互转---matlab实现
- Android与SQLite——实现简单登录
- c++ int转string方法
- DNS的查询过程
- Matlab搜索文件夹(包含子文件夹)下文本,提取文本并存储