C++学习笔记(41)
三、utime()库函数
utime()函数用于修改目录或文件的时间。
包含头文件:
#include <sys/types.h>
#include <utime.h>
函数声明:
int utime(const char *filename, const struct utimbuf *times);
utime()函数用来修改参数 filename 的 st_atime 和 st_mtime。如果参数 times 为空地址,则设置
为当前时间。结构 utimbuf 声明如下:
struct utimbuf
{
time_t actime;
time_t modtime;
};
返回值:0-成功,-1-失败,errno 被设置。 四、rename()库函数
rename()函数用于重命名目录或文件,相当于操作系统的 mv 命令。
包含头文件:
#include <stdio.h>
函数声明:
int rename(const char *oldpath, const char *newpath);
参数说明:
oldpath 原目录或文件名。
newpath 目标目录或文件名。
返回值:0-成功,-1-失败,errno 被设置。 五、remove()库函数
remove()函数用于删除目录或文件,相当于操作系统的 rm 命令。
包含头文件:
#include <stdio.h>
函数声明:
int remove(const char *pathname);
参数说明:
pathname 待删除的目录或文件名。
返回值:0-成功,-1-失败,errno 被设置。
312、Linux 的信号
一、信号的基本概念
信号(signal)是软件中断,是进程之间相互传递消息的一种方法,用于通知进程发生了事件,但是,
不能给进程传递任何数据。
信号产生的原因有很多,在 Shell 中,可以用 kill 和 killall 命令发送信号:
kill -信号的类型 进程编号
killall -信号的类型 进程名
二、信号的类型
信号名 信号值 默认处理动作 发出信号的原因
SIGHUP 1 A 终端挂起或者控制进程终止
SIGINT 2 A 键盘中断 Ctrl+c
SIGQUIT 3 C 键盘的退出键被按下
SIGILL 4 C 非法指令
SIGABRT 6 C 由 abort(3)发出的退出指令
SIGFPE 8 C 浮点异常
SIGKILL 9 AEF 采用 kill -9 进程编号 强制杀死程序。
SIGSEGV 11 CEF 无效的内存引用(数组越界、操作空指针和野指针等)。
SIGPIPE 13 A 管道破裂,写一个没有读端口的管道。
SIGALRM 14 A 由闹钟 alarm()函数发出的信号。
SIGTERM 15 A 采用“kill 进程编号”或“killall 程序名”通知程序。
SIGUSR1 10 A 用户自定义信号 1
SIGUSR2 12 A 用户自定义信号 2
SIGCHLD 17 B 子进程结束信号
SIGCONT 18 进程继续(曾被停止的进程)
SIGSTOP 19 DEF 终止进程
SIGTSTP 20 D 控制终端(tty)上按下停止键
SIGTTIN 21 D 后台进程企图从控制终端读
SIGTTOU 22 D 后台进程企图从控制终端写
其它 <=64 A 自定义信号
处理动作一项中的字母含义如下:
A 缺省的动作是终止进程。
B 缺省的动作是忽略此信号,将该信号丢弃,不做处理。
C 缺省的动作是终止进程并进行内核映像转储(core dump)。
D 缺省的动作是停止进程,进入停止状态的程序还能重新继续,一般是在调试的过程中。
E 信号不能被捕获。
F 信号不能被忽略。
三、信号的处理
进程对信号的处理方法有三种:
1)对该信号的处理采用系统的默认操作,大部分的信号的默认操作是终止进程。
2)设置信号的处理函数,收到信号后,由该函数来处理。
3)忽略某个信号,对该信号不做任何处理,就像未发生过一样。
signal()函数可以设置程序对信号的处理方式。
函数声明:
sighandler_t signal(int signum, sighandler_t handler);
参数 signum 表示信号的编号(信号的值)。
参数 handler 表示信号的处理方式,有三种情况:
1)SIG_DFL:恢复参数 signum 信号的处理方法为默认行为。
2)一个自定义的处理信号的函数,函数的形参是信号的编号。
3)SIG_IGN:忽略参数 signum 所指的信号。 四、信号有什么用
服务程序运行在后台,如果想让中止它,杀掉不是个好办法,因为进程被杀的时候,是突然死亡,没
有安排善后工作。
如果向服务程序发送一个信号,服务程序收到信号后,调用一个函数,在函数中编写善后的代码,程
序就可以有计划的退出。
如果向服务程序发送 0 的信号,可以检测程序是否存活。 五、信号应用示例
#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;
void EXIT(int sig)
{
cout << "收到了信号:" << sig << endl;
cout << "正在释放资源,程序将退出......\n";
// 以下是释放资源的代码。
cout << "程序退出。\n";
exit(0); // 进程退出。
}
int main(int argc,char *argv[])
{
// 忽略全部的信号,防止程序被信号异常中止。
for (int ii=1;ii<=64;ii++) signal(ii,SIG_IGN);
// 如果收到 2 和 15 的信号(Ctrl+c 和 kill、killall),本程序将主动退出。
signal(2,EXIT); signal(15,EXIT);
while (true)
{
cout << "执行了一次任务。\n";
sleep(1);
}
}
六、发送信号
Linux 操作系统提供了 kill 和 killall 命令向进程发送信号,在程序中,可以用 kill()函数向其它进程发
送信号。
函数声明:
int kill(pid_t pid, int sig);
kill()函数将参数 sig 指定的信号给参数 pid 指定的进程。
参数 pid 有几种情况:
1)pid>0 将信号传给进程号为 pid 的进程。
2)pid=0 将信号传给和当前进程相同进程组的所有进程,常用于父进程给子进程发送信号,注意,
发送信号者进程也会收到自己发出的信号。
3)pid=-1 将信号广播传送给系统内所有的进程,例如系统关机时,会向所有的登录窗口广播关机
信息。
sig:准备发送的信号代码,假如其值为 0 则没有任何信号送出,但是系统会执行错误检查,通常会
利用 sig 值为零来检验某个进程是否仍在运行。
返回值说明: 成功执行时,返回 0;失败返回-1,errno 被设置。
313、进程终止
有 8 种方式可以中止进程,其中 5 种为正常终止,它们是:
1)在 main()函数用 return 返回;
2)在任意函数中调用 exit()函数;
3)在任意函数中调用_exit()或_Exit()函数;
4)最后一个线程从其启动例程(线程主函数)用 return 返回;
5)在最后一个线程中调用 pthread_exit()返回;
异常终止有 3 种方式,它们是:
6)调用 abort()函数中止;
7)接收到一个信号;
8)最后一个线程对取消请求做出响应。 一、进程终止的状态
在 main()函数中,return 的返回值即终止状态,如果没有 return 语句或调用 exit(),那么该进程的
终止状态是 0。
在 Shell 中,查看进程终止的状态:echo $?
正常终止进程的 3 个函数(exit()和_Exit()是由 ISO C 说明的,_exit()是由 POSIX 说明的)。
void exit(int status);
void _exit(int status);
void _Exit(int status);
status 也是进程终止的状态。
如果进程被异常终止,终止状态为非 0。 服务程序的调度、日志和监控
二、资源释放的问题
retun 表示函数返回,会调用局部对象的析构函数,main()函数中的 return 还会调用全局对象的析
构函数。
exit()表示终止进程,不会调用局部对象的析构函数,只调用全局对象的析构函数。
exit()会执行清理工作,然后退出,_exit()和_Exit()直接退出,不会执行任何清理工作。 三、进程的终止函数
进程可以用 atexit()函数登记终止函数(最多 32 个),这些函数将由 exit()自动调用。
int atexit(void (*function)(void));
exit()调用终止函数的顺序与登记时相反。 进程退出前的收尾工作