• GCC的内存原子化操作函数接口

    1 原子化操作

    在并发编程中,一个操作或一组操作是原子操作、可线性化操作、不可分操作或不可中断操作(atomic, linearizable, indivisible, uniterruptible),表示该操作执行时不可被中断的。操作的原子性能够保证操作在执行时免受中断、信号、并发进程线程的影响。另外,原子操作大多只有两种结果,要么成功并改变系统中对应的状态,要么没有相关效果。

  • 在gdb中查看指定内存地址的内容

    调试 C/C++ 程序时,需要打印指定内存地址的内容。我最近调试程序中的序列化模块时,需要将类对象按照指定的格式转化为二进制流,为了验证转化结果,在调试时就需要将指定内存地址中的内容打印出来。

  • 同步和异步、阻塞和非阻塞

    1 同步和异步

    同步和异步指的是在进行I/O操作完成之前,是否允许其他处理步骤继续执行。
    计算机中的I/O操作相对于数据处理操作时十分耗时的。

    一个简单的I/O操作方式就是启动连接并等待操作完成,但是这样的操作(同步阻塞I/O)在通信过程中会阻塞进程的处理进度。
    相应的,可以在启动通信的同时进行其他的处理,并不需要等待I/O操作的完成,这样的操作就被称作是异步I/O。那些依赖于I/O操作执行完成的任务会阻塞等待I/O操作的完成,其他不依赖与I/O操作的任务能够继续执行。

    同步模型常用的函数接口: read , write , send , recv
    异步模型常用的函数接口: aio_write , aio_read

    1.1 POSIX AIO

    在头文件 aio.h 中定义,链接时使用 -lrt

    函数接口
    异步写操作

    int aio_read(struct aiocb* aiocbp);
    

    异步读操作

    int aio_write(struct aiocb* aiocbp);
    

    获取异步操作结果

    int aio_return(struct aiocb* aiocbp);
    

    获取异步操作中的错误

    int aio_error(struct aiocb* aiocbp);
    

    示例代码: github gist

    1.2 Linux AIO

    在头文件 libaio.h 中定义,链接时使用 -laio

    函数接口
    需要注意的是aio的函数接口需要借助 syscall 进行调用。
    创建aio context对象

    int io_setup(unsigned nr, aio_context_t* ctxp);
    

    销毁aio context对象

    int io_destroy(aio_context_t ctx);
    

    提交异步操作

    int io_submit(aio_context_t ctx, long nr, struct iocb** iocbpp);
    

    获取异步操作结果

    int io_getevents(aio_context_t ctx, long min_nr, long max_nr,
    		 io_event* events, struct timespec* timeout);
    

    示例代码:

    1.3 POSIX AIO与Linux AIO的区别

    摘自 stackoverflow.com

    On linux, the two AIO implementations are fundamentally different.
    The POSIX AIO is a user-level implementation that performs normal blocking I/O in multiple threads, hence giving the illusion that the I/Os are asynchronous. The main reason to do this is that:

    • it works with any filesystem
    • it works (essentially) on any operating system (keep in mind that gnu's libc is portable)
    • it works on files with buffering enabled (i.e. no ODIRECT flag set)

    The main drawback is that your queue depth (i.e. the number of outstanding operations you can have in practice) is limited by the number of threads you choose to have, which also means that a slow operation on one disk may block an operation going to a different disk. It also affects which I/Os (or how many) is seen by the kernel and the disk scheduler as well.
    The kernel AIO (i.e. iosubmit() et.al.) is kernel support for asynchronous I/O operations, where the io requests are actually queued up in the kernel, sorted by whatever disk scheduler you have, presumably some of them are forwarded (in somewhat optimal order one would hope) to the actual disk as asynchronous operations (using TCQ or NCQ). The main restriction with this approach is that not all filesystems work that well or at all with async I/O (and may fall back to blocking semantics), files have to be opened with ODIRECT which comes with a whole lot of other restrictions on the I/O requests. If you fail to open your files with ODIRECT, it may still "work", as in you get the right data back, but it probably isn't done asynchronously, but is falling back to blocking semantics.
    Also keep in mind that iosubmit() can actually block on the disk under certain circumstances.

    在Linux上两种AIO是完全不同的;
    POSIX AIO实现在用户层,实际上进行的操作是普通的多线程阻塞操作,表现为I/O操作是异步的,这种AIO的优点是兼容性和可移植性好,缺点是操作队列长度受限于最大线程数量。
    Linux AIO是内核提供的AIO函数接口,I/O操作请求的队列在内核中维护,这种AIO的缺点是并不支持所有的文件系统,Linux AIO在某些情况下的磁盘操作是会阻塞的。

    2 阻塞和非阻塞

    阻塞与非阻塞的概念针对的是函数是否会立即返回。
    非阻塞模型常与IO复用技术组合使用。
    可以通过函数将IO设备设置为非阻塞模式。

    3 如何理解阻塞非阻塞与同步异步的区别

    在处理 IO 的时候,阻塞和非阻塞都是同步 IO。
    只有使用了特殊的 API 才是异步 IO。

  • 查看Linux系统的相关信息

    查看Linux系统相关信息有助于排查和解决软件和硬件的兼容性问题。系统信息包括硬件信息和软件信息,硬件信息主要有CPU信息、内存信息、PCI信息、USB信息、硬盘信息等等。软件信息主要有系统版本、分区使用状态等等。本文主要介绍了获取当前Linux系统信息的命令。

    查看系统相关信息

    uname 指令提供了查询系统信息的功能,使用该命令能够快速获取操作系统信息概览。

    查看内核名称

    uname -s
    

    查看处理器类型

    uname -p
    

    查看硬件架构

    uname -i
    

    查看内核版本

    uname -r
    

    查看所有系统信息

    uname -a
    

    查看操作系统信息(发行版信息)

    cat /etc/os-release
    cat /proc/version
    lsb_release -a
    hostnamectl
    

    查看CPU相关信息

    lscpu 指令能够查看当前系统中CPU的详细信息,包括型号、主频、构架、大小端等信息。

    查看硬盘相关信息

    lsblk 指令能够查看块设备(block device)的详细信息,块设备主要指系统中的存储设备如硬盘和闪存。

    查看PCI设备的相关信息

    lspci 指令能够查看PCI设备的信息,PCI设备包括USB、显卡、串口、网卡等其他外围设备。

    输出树形结果

    lspci -t
    

    输出详细信息

    lspci -v
    lspci -vv
    

    查看USB设备的相关信息

    lsusb 指令能够查看USBS设备的信息。

    查看文件系统相关信息

    fdisk 命令能够查看和操作linux系统的分区表。

    查看文件系统信息

    fdisk -l
    

    df 命令能够查看分区信息和硬盘使用信息

    使输出信息更容易理解

    df -h
    
  • Linux常用命令行指令 - top

    linux的top命令能够动态显示当前系统的运行状态。它能够显示操作系统的汇总信息和当前系统上的正在运行的进程列表。

    统计信息说明

    (可以通过配置文件修改通计信息区的显示格式,下文所描述的都是在默认配置下的显示内容)

    第1行

    • 当前系统时间
    • 当前系统的启动时长
    • 当前登录的用户数量
    • 当前系统的平均负载(分别是1min,5min,10min的平均负载)

    这一行信息也可以通过 uptimew 指令获得

    第2行

    • 总进程数
    • 正在运行的进程数
    • 休眠的进程数
    • 停止的进程数
    • 僵尸进程数

    第3行

    • us 用户空间占用CPU百分比
    • sy 内核空间占用CPU百分比
    • ni 用户进程空间内改变过优先级的进程占用CPU百分比
    • id 空闲CPU百分比
    • wa 等待输入输出的CPU时间百分比
    • hi CPU服务于硬件中断所耗费的时间总额
    • si CPU服务软中断所耗费的时间总额
    • st Steal time 虚拟机被hypervisor偷去的CPU时间(如果当前处于一个hypervisor下的vm,实际上hypervisor也是要消耗一部分CPU处理时间的)

    第4行

    • 物理内存总量
    • 使用的物理内存总量
    • 空闲内存总量
    • 用作内核缓存的内存量

    第5行

    • 交换区总量
    • 使用的交换区总量
    • 空间交换区总量
    • 缓冲交换区总量

    进程信息

    在top命令中按f按可以查看显示的列信息,按对应字母来开启/关闭列,大写字母表示开启,小写字母表示关闭。带*号的是默认列。

    A: PID = (Process Id) 进程Id;
    E: USER = (User Name) 进程所有者的用户名;
    H: PR = (Priority) 优先级
    I: NI = (Nice value) nice值。负值表示高优先级,正值表示低优先级
    O: VIRT = (Virtual Image (kb)) 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
    Q: RES = (Resident size (kb)) 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
    T: SHR = (Shared Mem size (kb)) 共享内存大小,单位kb
    W: S = (Process Status) 进程状态。D=不可中断的睡眠状态,R=运行,S=睡眠,T=跟踪/停止,Z=僵尸进程
    K: %CPU = (CPU usage) 上次更新到现在的CPU时间占用百分比
    N: %MEM = (Memory usage (RES)) 进程使用的物理内存百分比
    M: TIME+ = (CPU Time, hundredths) 进程使用的CPU时间总计,单位1/100秒
    b: PPID = (Parent Process Pid) 父进程Id
    c: RUSER = (Real user name)
    d: UID = (User Id) 进程所有者的用户id
    f: GROUP = (Group Name) 进程所有者的组名
    g: TTY = (Controlling Tty) 启动进程的终端名。不是从终端启动的进程则显示为 ?
    j: P = (Last used cpu (SMP)) 最后使用的CPU,仅在多CPU环境下有意义
    p: SWAP = (Swapped size (kb)) 进程使用的虚拟内存中,被换出的大小,单位kb
    l: TIME = (CPU Time) 进程使用的CPU时间总计,单位秒
    r: CODE = (Code size (kb)) 可执行代码占用的物理内存大小,单位kb
    s: DATA = (Data+Stack size (kb)) 可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb
    u: nFLT = (Page Fault count) 页面错误次数
    v: nDRT = (Dirty Pages count) 最后一次写入到现在,被修改过的页面数
    y: WCHAN = (Sleeping in Function) 若该进程在睡眠,则显示睡眠中的系统函数名
    z: Flags = (Task Flags <sched.h>) 任务标志,参考 sched.h
    X: COMMAND = (Command name/line) 命令名/命令行

    参考资料

  • 云服务器安全相关配置

    我所租用的云服务器操作系统为CentOS Linux,在使用云服务器的过程中为了保证服务器的安全,进行了一些简单的配置,这样能够增加服务器被破解的难度。