目录
1.CPU核的信息获取
#include <sys/sysinfo.h>
int num = get_nprocs_conf(); /* Return number of configured processors. */
返回CPU当前可用的核心数量。
#include <sched.h>
int idx = sched_getcpu(); /* Get index of currently used CPU. */
返回CPU当前正使用的核心编号
2.CPU核的亲和性
#include <sched.h>
cpu_set_t cpuset; // 新建一个CPU集
CPU_ZERO(&cpuset); // 初始化这个CPU集
CPU_SET(3, &cpuset); // 将核3加入CPU集中
if(pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset) == 0)
// 设置亲和性(affinity),让线程thread 绑定cpuset
一个典型的将 Linux线程和CPU核绑定的 操作。现在线程thread就运行在核3上了。
更多函数如下:
void CPU_ZERO (cpu_set_t *set); //初始化,设为空
void CPU_SET (int cpu, cpu_set_t *set); //将某个cpu加入cpu集中
void CPU_CLR (int cpu, cpu_set_t *set); //将某个cpu从cpu集中移出
int CPU_ISSET (int cpu, const cpu_set_t *set); //判断某个cpu是否已在cpu集中设置了
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize,const cpu_set_t * cpuset );
// 设置 某线程的CPU亲和性
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t * cpuset );
// 获取 某线程的CPU亲和性
3.Linux线程的自动运行
需要注意的是,因为phread属于第三方库,编译的时候要加上选项:
-lpthread
如果是Qt项目,在pro文件中添加:
LIBS += -pthread
pthread线程在被创建后直接自动运行,默认是joinable可连接线程。只要main函数 (或者它们的调用者)不退出,就会一直运行。
4. select() 判断IO接口是否准备好
意义:传入要监听的文件描述符集合(可读、可写或异常,一般用于网络socket文件 或者 重要库文件)开始监听,select处于阻塞状态,当有事件发生或设置的等待时间timeout到了就会返回,返回之前自动去除集合中无事件发生的文件描述符,返回时传出有事件发生的文件描述符集合。
但select传出的集合并没有告诉用户集合中包括哪几个就绪的文件描述符,需要用户后续进行遍历操作。
函数原型
int select( int maxfdp, fd_set * readfds, fd_set * writefds, fd_set * errorfds, \
struct timeval * timeout );
maxfdp——传入参数,集合中所有文件描述符的范围,即最大文件描述符值+1
readfds——传入传出参数,select调用时传入要监听的可读文件描述符集合,select返回时传出发生可读事件的文件描述符集合
writefds——传入传出参数,select调用时传入要监听的可写文件描述符集合,select返回时传出发生可写事件的文件描述符集合
errorfds——传出参数,select返回时传出发生事件(包括可读和可写)中异常事件的文件描述符集合
timeout——传入参数,设置select阻塞的时间。若设置为NULL,则select一直阻塞直到有事件发生;
若设置为0,则select为非阻塞模式,执行后立即返回;
若设置为一个大于0的数,即select的阻塞时间,若阻塞时间内有事件发生就返回,否则时间到了立即返回
看个例子:
先获得IO或者文件描述符fd1和fd2(以相应的读写mode打开),再放入文件描述符集合rd或者wd里面。交给select()进行监视。
一般与select()搭配还会用到这几个宏:
void FD_ZERO(fd_set * fdset); //清空fdset中所有文件描述符
void FD_SET(int fd, fd_set * fdset); //添加文件描述符fd到集合fdset中
void FD_CLR(int fd, fd_set * fdset); //将文件描述符fd从集合fdset中去除
int FD_ISSET(int fd, fd_set * fdset); //判断文件描述符fd是否在集合fdset中
select()只有大于0,才说明确实等到事件发生了。这时用FD_ISSET()可以判断特定的文件或者IO是不是已经准备好了。
select()好就好在,可以在单进程的程序里,同时观察和监视好几个文件或者IO,而不必由用户自己进行多进程的设计。
参考: https://blog.csdn.net/weixin_49199646/article/details/109191381
5. 共享内存 mmap
Linux可以把文件映射到一块内存。所有对这块内存的读写改动,也会同步到该文件上。这样就可以让多个需要共享资源的进程读写这块共享内存,而不用频繁的打开关闭某个文件了。
例子:
核心就是mmap()函数。
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
返回值
成功:返回创建的映射区首地址
失败:MAP_FAILED宏
函数参数
- addr:指定映射的起始位置,通常设置成NULL,由系统指定
- length:映射到内存的文件长度
- prot:映射区的保护方式,最常用:
读:PROT_READ
写:PROT_WRITE
读写:PROT_READ | PROT_WRITE- flags:映射区的特性,可以是
MAP_SHARED:写入映射区的数据会写回文件,且允许其他映射该文件的进程共享
MAP_PRIVATE:对映射区的会产生一个映射区的复制(copy-on-write),对此区域所做的修改不会写回原文件。- fd:由open()返回的文件描述符,代表要映射的文件
- offset:以文件开始处的偏移量,必须是4k的整数倍,通常为0,表示从文件头开始映射。
得到了正确的内存指针addr,就可以对addr进行读写了。
另外为了获取文件长度,我们经常用lseek()来获取文件结尾位置,效果一样:
1) 欲将读写位置移到文件开头时: lseek(int fildes,0,SEEK_SET); 2) 欲将读写位置移到文件尾时: lseek(int fildes,0,SEEK_END); 3) 想要取得目前文件位置时: lseek(int fildes,0,SEEK_CUR); 当调用成功时则返回目前的读写位置,也就是距离文件开头多少个字节。若有错误则返回-1,errno 会存放错误代码。
6. ftruncate 改变文件大小
使用ftruncate()可以改变文件大小,一般是用来变大,为了接下来的操作做准备
例子:
int ftruncate(int fd,off_t length);
返回值
执行成功则返回0,失败返回-1,错误原因存于errno。参数
参数fd为已打开的文件描述词,而且必须是以写入模式打开的文件。
参数length是要改成的指定大小。
错误代码 errno
EBADF 参数fd文件描述词为无效的或该文件已关闭。
EINVAL 参数fd 为一socket 并非文件,或是该文件并非以写入模式打开。