• Linux常用命令行指令 - ipcs

    IPCinter process communication 的缩写,这项技术能够让进程间相互通信。
    Q:每个进程都有自己的地址空间和独立的用户空间,那么进程间是如何通信的呢?
    A:内核,也就是操作系统的心脏,它能够访问整个操作系统的内存。我们可以要求内核分配一块用于进程间交互的空间。

    几种进程间通信的方法

    进程间通信的方法有很多,有些支持同机器上进程的信息交互,有些支持跨机器的进程交互。

    • 管道 : pipes,管道提供了进程间交换信息的方法。
    • 共享内存 : shared memory,一个进程创建一块其他进程能够访问的内存空间,多个进程可以通过共享内存进行数据交换。
    • 消息队列 : message queue,消息队列是一个固定结构、有序的内存段,多个进程可以存放和取回数据。
    • 信号量 : semaphores,信号量提供了多进程访问同一资源的同步机制,信号量不负责传递数据,它协调对共享资源的访问。

    常用ipcs指令

    列出所有的IPC设备

    ipcs -a
    

    列出所有的消息队列

    ipcs -q
    

    列出所有的信号量

    ipcs -s
    

    列出所有的共享内存

    ipcs -m
    

    获取与IPC设备信息

    ipcs -q -i msq_id
    

    列出IPC设备的限制

    ipcs -l
    

    列出IPC设备的创建者和拥有者

    ipcs -m -c
    

    列出最近使用IPC设备的进程id

    ipcs -m -p
    

    列出IPC设备的最后访问时间

    ipcs -s -t
    

    列出IPC设备的当前使用状态

    ipcs -u
    
  • 使用gdb调试多线程程序

    查看当前线程信息

    将进程中的各个线程信息显示出来

    (gdb) info threads
    

    切换到指定进程

    (gdb) thread tid
    

    向指定的线程发送自定的指令

    (gdb) thread apply tid/all args
    

    常用的指定是查看所有线程的调用堆栈 thread apply all bt ,这个指令与 pstack 命令有些相似。

    gdb默认会自动捕捉新产生线程
    会在产生一个新的线程时会显示出LWP的字样提示用户,LWP = light weight process
    可以设置gdb是否提示线程相关的事件

    (gdb) set print thread-events on/off
    (gdb) show print thread-events
    

    为指定的线程设置断点

    含有多线程的程序,可以为单独的线程设置断点

    (gdb) break linespec thread tid
    

    任何时候当你的程序在GDB模式下停止的时候,包括当前调试线程的所有线程都会停下来,不会对继续对当前进程造成更改。这时你可以在线程间进行切换,查看整个进程的执行状况。

    Whenever your program stops under GDB for any reason, all threads of execution stop, not just the current thread. This allows you to examine the overall state of the program, including switching between threads, without worrying that things may change underfoot.

    防止gdb自动切换线程

    在调试gdb程序时,在单步执行时,会出现线程间跳转切换,这样对跟踪代码执行状态十分不方便。
    可以通过设置 scheduler-locking 让gdb在所调试的线程中运行,防止线程的自动切换。

    (gdb) set scheduler-locking step
    

    可以执行以下命令查看当前 scheduler-locking 的设置

    (gdb) show scheduler-locking
    

    scheduler-locking 有三种模式

    1. off 任何线程在任何时候都能执行
    2. on 只有当前线程能够执行
    3. step 为单步执行优化的模式,比较适合一般的调试

    Set the scheduler locking mode. If it is off, then there is no locking and any thread may run at any time. If on, then only the current thread may run when the inferior is resumed. The step mode optimizes for single-stepping. It stops other threads from "seizing the prompt" by preempting the current thread while you are stepping. Other threads will only rarely (or never) get a chance to run when you step. They are more likely to run when you `next' over a function call, and they are completely free to run when you use commands like `continue', `until', or `finish'. However, unless another thread hits a breakpoint during its timeslice, they will never steal the GDB prompt away from the thread that you are debugging.

  • 在gdb调试时忽略系统信号(signal)

    在gdb调试程序时,默认情况下gdb在收到信号时会中断程序的运行,并将收到的信号显示出来。这时,可以选择输入 c (continue)让程序继续运行。如果程序会重复收到这信号,会非常影响调试效率。可以通过配置忽略指定的系统信号。

    查看当前系统信号的处理信息的指令如下。

    (gdb) info signal
    

    以调试网络程序为例,进程会经常收到 SIGPIPE 消息,对于网络进程的 SIGPIPE 消息在程序中会由自身处理,可以使用以下指令让gdb不再提示 SIGPIPE 信号。

    (gdb) handle SIGPIPE nostop noprint
    

    其中, nostop 表示在收到信号时不再中断程序的运行, noprint 表示在收到信号时不再将收到的信号打印到gdb调试界面,这两个参数可以分开使用。

    参考资料: gnu gdb manual

    (全文完)

  • C++11新特性:基于范围的for循环

    在C++11中,介绍了一种新的for循环写法,基于范围的for循环。
    与旧的for循环类似,也是用来对遍历容器中的所有元素,新的写法更加简洁方便。可以使用auto自动适配容器中的内容。为了遍历容器时提高效率,在访问容器内部时可以声明为元素的引用,进而避免不必要的对象拷贝。示例代码如下(代码节选自 cppreferance

    std::vector<int> v = {0, 1, 2, 3, 4, 5};
    for (const int& i : v) // access by const reference
    {
        std::cout << i << ' ';
    }
    std::cout << '\n';
    
    for (auto i : v) // access by value, the type of i is int
    {
        std::cout << i << ' ';
    }
    std::cout << '\n';
    
    for (int n : {0, 1, 2, 3, 4, 5}) // the initializer may be a braced-init-list
    {
        std::cout << n << ' ';
    }
    std::cout << '\n';
    
    int a[] = {0, 1, 2, 3, 4, 5};
    for (int n : a) // the initializer may be an array
    {
        std::cout << n << ' ';
    }
    std::cout << '\n';
    
    for (int n : a)
    {
        std::cout << 1 << ' '; // the loop variable need not be used
    }
    std::cout << '\n';
    

    注意 std::map 的范围for循环遍历的写法
    std::map 中存放的是 key-value pair 键值对,所以在遍历的时候每次拿到的是一个 pair ,在访问其中的元素时,需要注意书写方法。示例代码如下。

    std::map<int, std::string> mapDemo;
    for (auto& kvp : mapDemo)
    {
        std::cout << kvp.first;
        std::cout << " - ";
        std::cout << kvp.second;
        std::cout << std::endl;
    }
    
  • Linux常用命令行指令 - scp

    scp 命令代表的是 secure copy,与 cp 命令的本地拷贝十分相似,主要区别就在于 scp 的路径可以是一个远程机器的路径。使用 scp 进行文件拷贝时,文件的传输时加密的。

    cp source_path dest_path
    

    从远程机器向本地拷贝

    以下命令会把 host 主机上的 src_path 文件拷贝到本地 dest_path 目录中。

    scp [email protected]:src_path dest_path
    

    从本地向远程机器拷贝

    以下命令会把本地 src_path 的文件拷贝打 host 主机上的 dest_path 路径上。

    scp src_path [email protected]:dest_path
    

    拷贝目录下的所有文件

    可以使用 -r 参数完成目录的递归拷贝, r 代表 recursive 递归。

    scp -r [email protected]:/src_path dest_path
    

    在拷贝时限制带宽

    可以使用 -l 参数限制传输的带宽, l 代表 limit 限制,限制带宽的单位是 kbps
    命令会在将拷贝传输的速度限制为 100kbps。

    scp -l 100 src_path dest_path
    
  • C++11新特性:自动类型推导

    关键字 auto 用于自动类型推导

    auto x=0;     // int
    auto c='a';   // char
    auto d=0.5;   // double
    

    自动类型推导主要用于声明比较复杂的变量,或者变量是在泛型编程(模板)中自动生成出来的。

    vector<int> vecNumbers;
    vector<int>::const_iterator it = vecNumbers.begin();
    auto it = vecNumbers.begin();
    

    auto 类型推导并不会指定 constvolatile 属性

    如果需要限定声明的变量为 constvolatile 属性,需要额外提供相应的关键字限定。因为编译器并不能推断出声明的变量是否具有常值属性和易失属性。

    volatile auto num=5;           // volatile int
    auto volatile const var=true;  //const valatile bool
    auto const ch='a';             // const char
    

    关键字 decltype 用于获取一个对量的类型

    使用 decltype 存储一个对象或表达式的类型, decltype 可以看做是 auto 的补充。

    vector<int> vecNumbers;
    typedef decltype(vecNumbers.begin()) Iterator;
    Iterator it2;
    

    函数返回值类型推导

    在C++11中可以使用 autodecltype 完成函数返回类型的推导。
    旧的函数声明格式 return_type func_name(param_type param, ...);
    新的函数声明格式示例如下,以下函数接收 bool 作为函数的参数,并返回 bool 类型的结果。

    auto func_name(bool bParam)->decltype(bParam)
    {
      return bParam;
    }
    

    函数返回值类型推导在模板泛型编程中非常有用,模板函数能够定义一个通用的返回类型,返回值类型会根据 decltype 自动推导。
    新的函数声明格式更易于维护,因为返回值并没有作为硬编码写入源文件中,但这样做可能会牺牲代码的可读性。

    template <class T>
    auto get_end(vector<T>& v) -> decltype(v.end())
    {
      return v.end();
    }
    
    vector<int> vecNumbers;
    auto it = get_end(vecNumbers);      // returns iterator
    
    const vector<int> vecNumbers2;
    auto it2 = get_enm(vecNumbers2);    // returns const_iterator