LINUX系统资源


时间

获取从1970-01-01 00:00:00以来的相隔秒数
#include <time.h> 
time_t time(time_t *tloc);
参数:
tloc:设为NULL就行了
返回值:
成功:秒数
失败:-1

可把time()得到的秒数变成一个struct tm结构体所表示的时间,结构体时间对应的是本地时间
struct tm *localtime_r(const time_t *timep, struct tm *result);
参数:
timep:需要进行转换的时间变量指针,可通过time()获取得到。
result:转换后用于存储信息的结构体指针
返回值:
成功:和参数result指针一样;
失败:NULL

struct tm
{ 
	int tm_sec; /* 秒(0-60) */ 
	int tm_min; /* 分(0-59) */ 
	int tm_hour; /* 时(0-23) */ 
	int tm_mday; /* 日(1-31) */ 
	int tm_mon; /* 月(0-11) */
	int tm_year; /* 年(这个值表示的是自1900年到现在经过的年数) */ 
	int tm_wday; /* 星期(0-6, 星期日Sunday = 0、星期一=1…) */ 
	int tm_yday; /* 一年里的第几天(0-365, 1 Jan = 0) */ 
	int tm_isdst; /* 夏令时 */ 
};

使用方法:
struct tm t; 
time_t sec = time(NULL); 
if (-1 == sec) 
{ 
	perror("time error"); 
	exit(-1); 
} 

localtime_r(&sec, &t);

随机数

#include <stdlib.h> 

int rand(void); //用于获取随机数
void srand(unsigned int seed);//为rand函数设置随机数种子

常用方式:
1、设置随机数种子
srand(time(NULL));
2、获取随机数
int num = rand();

休眠

#include <unistd.h> 
unsigned int sleep(unsigned int seconds);
参数:
seconds:休眠时间,以秒为单位

返回值:
休眠时间为参数seconds所指定的秒数,则返回0

被信号中断则返回剩余的秒数
#include <unistd.h> 

int usleep(useconds_t usec);

参数:
usec:休眠时间,以微秒为单位

返回值:
成功:0
失败:-1
#include <time.h> 
int nanosleep(const struct timespec *req, struct timespec *rem);

参数:
req:用于设置休眠时间长度,可精确到纳秒级别。
rem:用于记录剩余时间长度,可设置NULL

返回值:
成功休眠达到请求的时间间隔后,返回0
如果被信号中断或遇到错误,则返回-1,并将剩余时间记录参数rem的结构体变量中
(参数rem不为NULL的情况下,如果为NULL表示不接收剩余时间)

struct timespec 
{ 
	time_t tv_sec; /* 秒 */ 
	syscall_slong_t tv_nsec; /* 纳秒 */ 
};

内存分配

#include <stdlib.h> 

void *calloc(size_t nmemb, size_t size);//用来动态地分配内存空间并初始化为0
动态地分配nmemb个长度为size的连续空间,并将每一个字节都初始化为0
所以是分配nmemb * size个字节长度的内存空间,并且每个字节的值都是0

返回值:
成功:返回内存地址
失败:NULL

proc文件系统

proc文件系统是一个虚拟文件系统,以文件系统的方式为应用层访问系统内核数据提供接口,用户和应用程序可以通过proc文件系统得到系统信息和进程相关信息

与普通文件不同的是,proc文件系统是动态创建的,文件本身并不存在于磁盘当中,只存在于内存当中,与devfs一样,都被称为虚拟文件系统。

proc目录以数字命名的文件夹,对应的其实是进程的PID号

文件记录的信息和意思如下:
⚫ cmdline:内核启动参数;
⚫ cpuinfo:CPU相关信息;
⚫ iomem:IO设备的内存使用情况;
⚫ interrupts:显示被占用的中断号和占用者相关的信息;
⚫ ioports:IO端口的使用情况;
⚫ kcore:系统物理内存映像,不可读取;
⚫ loadavg:系统平均负载;
⚫ meminfo:物理内存和交换分区使用情况;
⚫ modules:加载的模块列表;
⚫ mounts:挂载的文件系统列表;
⚫ partitions:系统识别的分区表;
⚫ swaps:交换分区的利用情况;
⚫ version:内核版本信息;
⚫ uptime:系统运行时间;


信号

基本概念

信号:事件发生时对进程的通知机制,也可以把它称为软件中断。大多数情况下,无法预测信号达到的准确时间。

作用:用来通信

常用信号

SIGINT
按下CTRL + C,内核会发送SIGINT信号给前台进程组的每一个进程,该信号的系统默认操作是终止进程的运行
使用SIGINT信号虽然能终止进程,但是前提条件是该进程并没有忽略或捕获该信号

SIGABRT
当进程调用abort()时(进程异常终止),系统会向该进程发送SIGABRT信号,该信号的系统默认操作是终止进程、并生成核心转储文件

SIGBUS
bus error(总线错误),表示发生了内存访问错误,该信号的系统默认操作是终止进程

SIGFPE
该信号因特定类型的算术错误而产生,譬如除以0,该信号的系统默认操作是终止进程

SIGKILL
此信号为“必杀(sure kill)”信号,用于杀死进程的终极办法,此信号无法被进程阻塞、忽略或者捕获,故而“一击必杀”,总能终止进程
如果使用SIGINT或SIGQUIT信号无法终止进程,则使用SIGKILL信号。
“kill -9 pid”,-9指是发送编号为9的信号,也就是SIGKILL信号

SIGSEGV
应用程序对内存进行引用无效时,操作系统会向该应用程序发送该信号,系统默认操作是终止进程。
内存无效引用的原因:
1、解引用的指针里包含了错误地址(譬如,未初始化的指针)
2、传递无效参数供函数调用

SIGPIPE
涉及管道和socket,当进程向已经关闭的管道、FIFO或套接字写入信息时,系统将发送该信号给进程,该信号的系统默认操作是终止进程

SIGALRM
应用程序调用alarm()或setitimer()函数设置定时器,当定时器定时时间到,内核将会发送SIGALRM信号给该应用程序,该信号的系统默认操作是终止进程

SIGTERM
进程终止的标准信号,kill命令所发送的默认信号(kill pid),精心设计的应用程序应该捕获SIGTERM信号、为其绑定处理函数。当收到SIGTERM信号时,在处理函数中清除临时文件以及释放其它资源,再而退出程序

SIGCHLD
父进程的子进程终止时,内核会向父进程发送该信号,或者子进程因收到别的信号而暂停或恢复时,内核也可能向父进程发送SIGCHLD信号,系统默认操作是忽略此信号
如果父进程希望获取子进程状态改变,则应捕获此信号

SIGCLD
与SIGCHLD信号同义

SIGCONT
已停止的进程接收到此信号,将会恢复运行
不处于停止状态的进程接收到此信号,系统默认操作是忽略该信号

SIGSTOP
“必停”信号,用于停止进程(停止不是终止,停止只是暂停运行、进程并没有终止),应用程序无法将该信号忽略或者捕获,故而总能停止进程

SIGTSTP
停止信号,按下CTRL + Z,系统会将SIGTSTP信号发送给前台进程组中的每一个进程,使其停止运行。

SIGXCPU
进程的CPU时间超出对应的资源限制时,内核将发送此信号给进程

SIGVTALRM
应用程序调用setitimer()函数设置虚拟定时器,当定时器定时时间到时,内核将会发送该信号给进程

SIGWINCH
在窗口环境中,当终端窗口尺寸发生变化时(譬如用户手动调整了大小,应用程序调用ioctl()设置了大小等),系统会向前台进程组中的每一个进程发送该信号

SIGPOLL/SIGIO(两个信号同义)
用于提示异步IO事件的发生,如应用程序打开的文件描述符发生I/O事件时,内核会向应用程序发送SIGIO信号

SIGSYS
如果进程发起的系统调用有误,那么内核将发送该信号给对应的进程。


分类

在这里插入图片描述


宏定义

信号本质上是int类型的数字编号,好比硬件中断对应的中断号,从数字1开始顺序展开。

信号在<signum.h>头文件中定义,每个信号都是以SIGxxx开头

/* Signals. */ 
#define SIGINT 2 /* Interrupt (ANSI). */ 
#define SIGQUIT 3 /* Quit (POSIX). */
#define SIGILL 4 /* Illegal instruction (ANSI). */ 
#define SIGTRAP 5 /* Trace trap (POSIX). */ 
#define SIGABRT 6 /* Abort (ANSI). */ 
#define SIGIOT 6 /* IOT trap (4.2 BSD). */ 
#define SIGBUS 7 /* BUS error (4.2 BSD). */ 
#define SIGFPE 8 /* Floating-point exception (ANSI). */ 
#define SIGKILL 9 /* Kill, unblockable (POSIX). */ 
#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ 
#define SIGSEGV 11 /* Segmentation violation (ANSI). */ 
#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ 
#define SIGPIPE 13 /* Broken pipe (POSIX). */ 
#define SIGALRM 14 /* Alarm clock (POSIX). */ 
#define SIGTERM 15 /* Termination (ANSI). */ 
#define SIGSTKFLT 16 /* Stack fault. */ 
#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ 
#define SIGCHLD 17 /* Child status has changed (POSIX). */ 
#define SIGCONT 18 /* Continue (POSIX). */ 
#define SIGSTOP 19 /* Stop, unblockable (POSIX). */
#define SIGTSTP 20 /* Keyboard stop (POSIX). */ 
#define SIGTTIN 21 /* Background read from tty (POSIX). */ 
#define SIGTTOU 22 /* Background write to tty (POSIX). */ 
#define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ 
#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ 
#define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ 
#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ 
#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ 
#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ 
#define SIGPOLL SIGIO /* Pollable event occurred (System V). */
#define SIGIO 29 /* I/O now possible (4.2 BSD). */ 
#define SIGPWR 30 /* Power failure restart (System V). */ 
#define SIGSYS 31 /* Bad system call. */ 
#define SIGUNUSED 31

在这里插入图片描述


信号处理设置函数

#include <signal.h> 

typedef void (*sig_t)(int);sig_t函数指针的int形参是触发函数的信号宏)

sig_t signal(int signum, sig_t handler);

函数参数和返回值含义如下:
signum:需要设置的信号

handler:信号处理函数或方法
需要执行自定义的函数,填写函数指针进去即可
忽略信号填,SIG_IGN
系统默认操作填,SIG_DFL

/* Fake signal functions. */
#define SIG_ERR ((sig_t) -1) /* Error return. */
#define SIG_DFL ((sig_t) 0) /* Default action. */
#define SIG_IGN ((sig_t) 1) /* Ignore signal. */

返回值:
成功:返回信号处理函数指针
出错:返回SIG_ERR
#include <signal.h> 
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

函数参数和返回值含义如下:
signum:需要设置的信号,除了SIGKILL信号和SIGSTOP信号之外的任何信号
act:结构体指针,该结构体描述了信号的处理方式
不为NULL:设置信号新的处理方式
NULL:无需改变信号当前的处理方式

oldact:结构体指针
不为NULL:获取之前的信号处理信息
NULL:不获取信息

返回值:
成功:0
失败:-1

struct sigaction 
{ 
	//sa_handler和sa_sigaction是互斥的,不能同时设置
	//对于标准信号来说,使用sa_handler就可以了,可通过SA_SIGINFO标志进行选择。
	void (*sa_handler)(int);  //信号处理函数
	
	void (*sa_sigaction)(int, siginfo_t *, void *);  //信号处理函数
	
	sigset_t sa_mask; 
	int sa_flags; void (*sa_restorer)(void); 
};

发送信号kill

进程将信号发送给另一个进程是需要权限的,并不是可以随便给任何一个进程发送信号

超级用户root进程可以将信号发送给任何进程

但非超级用户(普通用户)进程来说,其基本规则是发送者进程的实际用户ID或有效用户ID必须等于接收者进程的实际用户ID或有效用户ID。

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

int kill(pid_t pid, int sig);
参数:
pid为正,信号sig将发送到pid指定的进程
等于0,将sig发送到当前进程的进程组中的每个进程
等于-1,将sig发送到当前进程有权发送信号的每个进程,但进程1(init)除外。
小于-1,将sig发送到ID为-pid的进程组中的每个进程。

sig:需要发送的信号
设置为0则表示不发送信号,但仍执行错误检查,通常用于检测进程(pid)是否存在。

返回值:
成功:0
失败:-1,并设置errno。
#include <signal.h> 

//进程向自身发送信号
int raise(int sig);  相当于等于kill(getpid(), sig);

参数:
sig:信号

返回值:
成功:0
失败:非零值

信号定时器

设置定时器,当定时时间到,内核会向进程发送SIGALRM信号
#include <unistd.h> 
unsigned int alarm(unsigned int seconds);

参数:
seconds:定时时间,以秒为单位;如果等于0,则表示取消之前设置的alarm闹钟

返回值:

调用alarm()时,之前已设置有alarm闹钟并还没有超时,则之前闹钟的剩余值为返回值
并且之前设置的闹钟使劲按被新的替代

返回0则代表正常情况

Ps:
alarm闹钟不能循环触发,只能触发一次
要实现循环触发,可以在SIGALRM信号处理函数中再次调用alarm()函数设置定时器

信号等待

进程暂停运行、进入休眠状态,直到捕获到信号为止,执行完信号处理函数后,pause()才会返回
#include <unistd.h> 

int pause(void);

信号集

信号集是sigset_t类型的结构体,该结构体其实就是一个无符号长整形数组

#define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int))) 

typedef struct { 
	unsigned long int __val[_SIGSET_NWORDS]; 
}sigset_t;

初始化


#include <signal.h> 

//都用于初始化信号集
int sigemptyset(sigset_t *set);  //初始化信号集 但 不包含任何信号
int sigfillset(sigset_t *set);	 //初始化信号集 并 包含所有信号(包括所有实时信号) 

参数:
set:指向需要进行初始化的信号集变量

返回值:
成功:0
失败:-1

添加/删除

#include <signal.h> 
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);

参数:
set:指向信号集。
signum:需要添加/删除的信号

返回值:
成功:0
失败:-1

检测是否拥有

测试某个信号是否在信号集中,
#include <signal.h> 
int sigismember(const sigset_t *set, int signum);

参数:
set:指定信号集。
signum:需要进行测试的信号

返回值:
在:1
不在:0
失败:-1

示例

sigset_t sig_set; 
//初始化信号集
sigemptyset(&sig_set); 
//添加信号
sigaddset(&sig_set, SIGINT);
//删除信号
sigdelset(&sig_set, SIGINT);

信号掩码

一个用于存放某些信号需要被阻塞的信号集

如果信号被加入到阻塞掩码中,内核会将其阻塞使其无法传递给进程进行处理,直到该信号从信号掩码中移除,内核才会把该信号传递给进程从而得到处理

#include <signal.h> 
//用于在信号掩码钟添加或移除信号集
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
参数:
how:指定了函数的具体操作
set:信号集内的所有信号添加到信号掩码中或者从信号掩码中移除;为NULL,则表示无需对当前信号掩码作出改动。
oldset:用于获取进程当前的信号掩码,为NULL则不获取当前的信号掩码。

返回值:
成功:0
失败:-1

参数how可以设置为以下宏:
⚫ SIG_BLOCK:将参数set指向的信号集内所有信号添加到进程的信号掩码中。换言之,将信号掩码设置为当前值与set的并集。
⚫ SIG_UNBLOCK:将参数set指向信号集内的所有信号从进程信号掩码中移除。
⚫ SIG_SETMASK:进程信号掩码直接设置为参数set指向的信号集。

在一些关键性代码段中,不想被某些信号所影响就会把这些信号加入到信号掩码中,等执行完临界代码以后,才会将信号移出信号掩码中,这时候有可能我们就会想在移除动作后,等待信号响应完再继续执行程序,使用pause()进行信号等待,但存在一个问题就是:信号传递恰好发生在第二次调用sigprocmask()移除之后、pause()之前,这时候就会先执行信号处理函数,再执行pause()进行信号等待,导致了得下一次信号发生时候,pause()才会退出,为了解决这个问题,需要将sigprocmask和pause封装成一个动作那就是sigsuspend()函数

int ret;
sigset_t new_set, old_set; 

/* 信号集初始化 */ 
sigemptyset(&new_set); 

/* 向信号掩码中添加信号 */ 
sigaddset(&new_set, SIGINT);  
ret = sigprocmask(SIG_BLOCK, &new_set, &old_set);
if(ret == -1) 
	exit(-1); 
	
/* 受保护的关键代码段 */ 
...... 
/**********************/ 

/* 恢复信号掩码 */ 
ret = sigprocmask(SIG_SETMASK, &old_set, NULL);
if(ret == -1) 
	exit(-1); 
	
/* 等待信号唤醒 */
pause(); <-这里会有可能存在一个bug(应该用sigsuspend函数)
#include <signal.h> 
int sigsuspend(const sigset_t *mask);
参数mask的信号集会临时替换进程的信号掩码,然后挂起进程,直到捕获到信号被唤醒(如果捕获的信号是mask信号集中的成员,将不会唤醒、继续挂起),进入到信号处理函数。信号处理函数返回后,会将进程的信号掩码恢复成调用前的值
参数:
mask:临时的信号掩码(信号集)
返回值:
始终返回-1,并设置errno来指示错误(通常为EINTR),表示被信号所中断
调用失败:将errno设置为EFAULT

相当于:
sigprocmask(SIG_SETMASK, &mask, &old_mask); 
pause(); 
sigprocmask(SIG_SETMASK, &old_mask, NULL);

等待信号集

被阻塞、等待被处理、处于等待状态信号都会被放入等待信号集

#include <signal.h> 
//获取等待信号集
int sigpending(sigset_t *set);
参数:
set:用于存储等待状态的信号集

返回值:
成功:0
失败:-1

异常退出

使用abort()函数,内核会向进程发送SIGABRT信号
无论设置了阻塞或忽略SIGABRT信号,abort()调用均不收到影响,总会成功终止进程

#include <stdlib.h> 
//终止进程运行,生成核心转储文件
void abort(void);
  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值