• linux下面编写简单的c++程序


       linux 下面跑c++ 需要安装GNU 的 C/C++ 编译器。GNU 的 gcc 编译器适合于 C 和 C++ 编程语言。

      gcc 和 g++ 的区别无非就是调用的编译器不同, 并且传递给链接器的参数不同。具体而言g++ 会把 .c 文件当做是 C++ 语言 (在 .c 文件前后分别加上 -xc++ 和 -xnone, 强行变成 C++), 从而调用 cc1plus 进行编译。g++ 遇到 .cpp 文件也会当做是 C++, 调用 cc1plus 进行编译. g++ 还会默认告诉链接器, 让它链接上 C++ 标准库。gcc 会把 .c 文件当做是 C 语言. 从而调用 cc1 进行编译.gcc 遇到 .cpp 文件, 会处理成 C++ 语言. 调用 cc1plus 进行编译. gcc 默认不会链接上 C++ 标准库.

    例如查看自己相关版本:

    [root@bogon ctest]# g++ -v
    Using built-in specs.
    COLLECT_GCC=g++
    COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
    Target: x86_64-redhat-linux
    Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
    Thread model: posix
    gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
    [root@bogon ctest]# gcc -v
    Using built-in specs.
    COLLECT_GCC=gcc
    COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
    Target: x86_64-redhat-linux
    Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux
    Thread model: posix
    gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)

    1. 测试linux 运行第一个c++ 程序

    1. helloworld

    1. 源码hello.cpp

    #include <iostream>
    
    int main()
    {
        std::cout << "Hello World!\n";
        return 0;
    }

    2. 编译

    [root@bogon ctest]# g++ hello.cpp 
    [root@bogon ctest]# ll
    total 16
    -rwxr-xr-x. 1 root root 8800 Nov 20 21:32 a.out
    -rw-r--r--. 1 root root   85 Nov 20 21:30 hello.cpp

      默认生成 a.out

    3. 直接运行

    [root@bogon ctest]# ./a.out 
    Hello World!

    4. 也可以编译时指定输出

    [root@bogon ctest]# g++ -o hello hello.cpp 
    [root@bogon ctest]# ll
    total 28
    -rwxr-xr-x. 1 root root 8800 Nov 20 21:32 a.out
    -rwxr-xr-x. 1 root root 8800 Nov 20 21:33 hello
    -rw-r--r--. 1 root root   85 Nov 20 21:30 hello.cpp
    [root@bogon ctest]# ./hello 
    Hello World!

    5. strace 跟踪执行指令

    [root@bogon ctest]# strace -ff ./a.out 
    execve("./a.out", ["./a.out"], 0x7ffc3eae64a8 /* 26 vars */) = 0
    brk(NULL)                               = 0x9b6000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fedc008a000
    access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=27766, ...}) = 0
    mmap(NULL, 27766, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fedc0083000
    close(3)                                = 0
    open("/lib64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\264\5\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=995840, ...}) = 0
    mmap(NULL, 3175456, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fedbfb62000
    mprotect(0x7fedbf65f000, 2093056, PROT_NONE) = 0
    mmap(0x7fedbf85e000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14000) = 0x7fedbf85e000
    close(3)                                = 0
    open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`&\2\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=2156352, ...}) = 0
    mmap(NULL, 3985920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fedbf27c000
    mprotect(0x7fedbf440000, 2093056, PROT_NONE) = 0
    mmap(0x7fedbf63f000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c3000) = 0x7fedbf63f000
    mmap(0x7fedbf645000, 16896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fedbf645000
    close(3)                                = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fedc0081000
    mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fedc007f000
    arch_prctl(ARCH_SET_FS, 0x7fedc007f740) = 0
    mprotect(0x7fedbf63f000, 16384, PROT_READ) = 0
    mprotect(0x7fedbf85e000, 4096, PROT_READ) = 0
    mprotect(0x7fedbfb60000, 4096, PROT_READ) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fedc007e000
    mprotect(0x7fedbfe4b000, 32768, PROT_READ) = 0
    mprotect(0x600000, 4096, PROT_READ)     = 0
    mprotect(0x7fedc008b000, 4096, PROT_READ) = 0
    munmap(0x7fedc0083000, 27766)           = 0
    fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fedc0089000
    write(1, "Hello World!\n", 13Hello World!
    )          = 13
    exit_group(0)                           = ?
    +++ exited with 0 +++

    2. 线程相关  

    1. 源代码

    thread.cpp

    #include <iostream>
    #include <thread>
    using namespace std;
    
    void addNum(int i) {
        cout << std::this_thread::get_id() << " num: " << i << endl;
    }
    
    int main()
    {
        cout << "main " << std::this_thread::get_id() << endl;
        thread t(addNum, 1);
        t.join();
    
        return 0;
    }

    2. 编译

    [root@bogon ctest]# g++ -std=c++11 -pthread -o thread ./thread.cpp 
    [root@bogon ctest]# ll | grep thread
    -rwxr-xr-x. 1 root root 50208 Nov 20 21:40 thread
    -rw-r--r--. 1 root root   277 Nov 20 21:37 thread.cpp

      这里需要注意需要加参数-std=c++11 -pthread, 我的没加参数报编译问题, 不加-pthread 运行时报权限不足问题。

    3. 运行

    [root@bogon ctest]# ./thread 
    main 139712543106880
    139712526198528 num: 1

    4. strace 追踪执行过程

    [root@bogon ctest]# strace -ff ./thread
    execve("./thread", ["./thread"], 0x7ffe94de6758 /* 26 vars */) = 0
    brk(NULL)                               = 0x14df000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f846c0bb000
    access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=27766, ...}) = 0
    mmap(NULL, 27766, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f846c0b4000
    close(3)                                = 0
    open("/lib64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\264\5\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=995840, ...}) = 0
    mmap(NULL, 3175456, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f846bb93000
    mprotect(0x7f846bc7c000, 2097152, PROT_NONE) = 0
    mmap(0x7f846be7c000, 40960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xe9000) = 0x7f846be7c000
    mmap(0x7f846be86000, 82976, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f846be86000
    close(3)                                = 0
    open("/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0PS\0\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=1136944, ...}) = 0
    mmap(NULL, 3150136, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f846b891000
    mprotect(0x7f846b992000, 2093056, PROT_NONE) = 0
    mmap(0x7f846bb91000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x100000) = 0x7f846bb91000
    close(3)                                = 0
    open("/lib64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320*\0\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=88720, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f846c0b3000
    mmap(NULL, 2184192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f846b67b000
    mprotect(0x7f846b690000, 2093056, PROT_NONE) = 0
    mmap(0x7f846b88f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14000) = 0x7f846b88f000
    close(3)                                = 0
    open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200m\0\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=142144, ...}) = 0
    mmap(NULL, 2208904, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f846b45f000
    mprotect(0x7f846b476000, 2093056, PROT_NONE) = 0
    mmap(0x7f846b675000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16000) = 0x7f846b675000
    mmap(0x7f846b677000, 13448, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f846b677000
    close(3)                                = 0
    open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
    read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`&\2\0\0\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=2156352, ...}) = 0
    mmap(NULL, 3985920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f846b091000
    mprotect(0x7f846b255000, 2093056, PROT_NONE) = 0
    mmap(0x7f846b454000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c3000) = 0x7f846b454000
    mmap(0x7f846b45a000, 16896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f846b45a000
    close(3)                                = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f846c0b2000
    mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f846c0b0000
    arch_prctl(ARCH_SET_FS, 0x7f846c0b0740) = 0
    mprotect(0x7f846b454000, 16384, PROT_READ) = 0
    mprotect(0x7f846b675000, 4096, PROT_READ) = 0
    mprotect(0x7f846b88f000, 4096, PROT_READ) = 0
    mprotect(0x7f846bb91000, 4096, PROT_READ) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f846c0af000
    mprotect(0x7f846be7c000, 32768, PROT_READ) = 0
    mprotect(0x604000, 4096, PROT_READ)     = 0
    mprotect(0x7f846c0bc000, 4096, PROT_READ) = 0
    munmap(0x7f846c0b4000, 27766)           = 0
    set_tid_address(0x7f846c0b0a10)         = 3555
    set_robust_list(0x7f846c0b0a20, 24)     = 0
    rt_sigaction(SIGRTMIN, {sa_handler=0x7f846b465860, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f846b46e630}, NULL, 8) = 0
    rt_sigaction(SIGRT_1, {sa_handler=0x7f846b4658f0, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, sa_restorer=0x7f846b46e630}, NULL, 8) = 0
    rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
    getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
    futex(0x7f846be9896c, FUTEX_WAKE_PRIVATE, 2147483647) = 0
    futex(0x7f846be98978, FUTEX_WAKE_PRIVATE, 2147483647) = 0
    fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f846c0ba000
    write(1, "main 140206725072704\n", 21main 140206725072704
    )  = 21
    brk(NULL)                               = 0x14df000
    brk(0x1500000)                          = 0x1500000
    brk(NULL)                               = 0x1500000
    mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f846a890000
    mprotect(0x7f846a890000, 4096, PROT_NONE) = 0
    clone(child_stack=0x7f846b08ffb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f846b0909d0, tls=0x7f846b090700, child_tidptr=0x7f846b0909d0) = 3556
    strace: Process 3556 attached
    [pid  3555] futex(0x7f846b0909d0, FUTEX_WAIT, 3556, NULL <unfinished ...>
    [pid  3556] set_robust_list(0x7f846b0909e0, 24) = 0
    [pid  3556] write(1, "140206708164352 num: 1\n", 23140206708164352 num: 1
    ) = 23
    [pid  3556] madvise(0x7f846a890000, 8368128, MADV_DONTNEED) = 0
    [pid  3556] exit(0)                     = ?
    [pid  3556] +++ exited with 0 +++
    <... futex resumed>)                    = 0
    exit_group(0)                           = ?
    +++ exited with 0 +++

      可以看到创建线程是通过clone 创建出一个子进程来进行的,查看clone 函数:

    [root@bogon ctest]# man 2 clone
    CLONE(2)                                    Linux Programmer's Manual                                    CLONE(2)
    
    NAME
           clone, __clone2 - create a child process
    
    SYNOPSIS
           /* Prototype for the glibc wrapper function */
    
           #include <sched.h>
    
           int clone(int (*fn)(void *), void *child_stack,
                     int flags, void *arg, ...
                     /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
    
           /* Prototype for the raw system call */
    
           long clone(unsigned long flags, void *child_stack,
                     void *ptid, void *ctid,
                     struct pt_regs *regs);
    
       Feature Test Macro Requirements for glibc wrapper function (see feature_test_macros(7)):
    
           clone():
               Since glibc 2.14:
                   _GNU_SOURCE
               Before glibc 2.14:
                   _BSD_SOURCE || _SVID_SOURCE
                       /* _GNU_SOURCE also suffices */
    
    DESCRIPTION
           clone() creates a new process, in a manner similar to fork(2).

    3. 线程间通信相关

      简单的实现基于锁、加条件的阻塞加通知。

    1. 源码

    #include <iostream>
    #include <mutex>
    #include <condition_variable>
    #include <thread>
    
    using namespace std;
    
    
    std::mutex _mutex;
    std::condition_variable cond1;
    
    
    void addNum() {
        std::unique_lock<std::mutex> lock(_mutex);
        cout << std::this_thread::get_id() << " wait" << endl;
        cond1.wait(lock);
        cout << std::this_thread::get_id() << " end wait" << endl;
    }
    
    int main()
    {
        cout << "main " << std::this_thread::get_id() << endl;
        thread t(addNum);
        t.detach();
    
        cout << "main " << std::this_thread::get_id() << " sleep" << endl;
        this_thread::sleep_for(std::chrono::seconds(3));
    
        std::unique_lock<std::mutex> lock(_mutex);
        cond1.notify_all();
        lock.unlock(); 
        this_thread::sleep_for(std::chrono::seconds(3));
        cout << "main " << std::this_thread::get_id() << " end" << endl;
        return 0;
    }

    2. 编译

    [root@bogon ctest]# g++ -std=c++11 -pthread -o thread2 ./thread2.cpp 
    [root@bogon ctest]# ll | grep thread2
    -rwxr-xr-x. 1 root root 51232 Nov 20 23:19 thread2
    -rw-r--r--. 1 root root   836 Nov 20 23:18 thread2.cpp

    3. 运行

    [root@bogon ctest]# ./thread2 
    main 140404650915648
    main 140404650915648 sleep
    140404634007296 wait
    140404634007296 end wait
    main 140404650915648 end

    4. strace  查看

    [root@bogon ctest]# strace -ff -o thread2 ./thread2 
    main 140421628819264
    main 140421628819264 sleep
    140421611910912 wait
    140421611910912 end wait
    main 140421628819264 end
    [root@bogon ctest]# ll
    total 140
    -rwxr-xr-x. 1 root root  8800 Nov 20 21:33 hello
    -rw-r--r--. 1 root root    85 Nov 20 21:30 hello.cpp
    -rwxr-xr-x. 1 root root 50192 Nov 20 21:50 thread
    -rwxr-xr-x. 1 root root 51232 Nov 20 23:19 thread2
    -rw-r--r--. 1 root root  6171 Nov 20 23:26 thread2.8478
    -rw-r--r--. 1 root root   348 Nov 20 23:26 thread2.8479
    -rw-r--r--. 1 root root   836 Nov 20 23:18 thread2.cpp
    -rw-r--r--. 1 root root   277 Nov 20 21:49 thread.cpp

      可以看到生成了两个文件, 两个线程对应两个文件。 查看:

    8478:

     1 execve("./thread2", ["./thread2"], 0x7ffdaa1e9c88 /* 26 vars */) = 0
     2 brk(NULL)                               = 0x13c7000
     3 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6754ea000
     4 access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
     5 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
     6 fstat(3, {st_mode=S_IFREG|0644, st_size=27766, ...}) = 0
     7 mmap(NULL, 27766, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fb6754e3000
     8 close(3)                                = 0
     9 open("/lib64/libstdc++.so.6", O_RDONLY|O_CLOEXEC) = 3
    10 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\264\5\0\0\0\0\0"..., 832) = 832
    11 fstat(3, {st_mode=S_IFREG|0755, st_size=995840, ...}) = 0
    12 mmap(NULL, 3175456, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb674fc2000
    13 mprotect(0x7fb6750ab000, 2097152, PROT_NONE) = 0
    14 mmap(0x7fb6752ab000, 40960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xe9000) = 0x7fb6752ab000
    15 mmap(0x7fb6752b5000, 82976, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb6752b5000
    16 close(3)                                = 0
    17 open("/lib64/libm.so.6", O_RDONLY|O_CLOEXEC) = 3
    18 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0PS\0\0\0\0\0\0"..., 832) = 832
    19 fstat(3, {st_mode=S_IFREG|0755, st_size=1136944, ...}) = 0
    20 mmap(NULL, 3150136, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb674cc0000
    21 mprotect(0x7fb674dc1000, 2093056, PROT_NONE) = 0
    22 mmap(0x7fb674fc0000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x100000) = 0x7fb674fc0000
    23 close(3)                                = 0
    24 open("/lib64/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
    25 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320*\0\0\0\0\0\0"..., 832) = 832
    26 fstat(3, {st_mode=S_IFREG|0755, st_size=88720, ...}) = 0
    27 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6754e2000
    28 mmap(NULL, 2184192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb674aaa000
    29 mprotect(0x7fb674abf000, 2093056, PROT_NONE) = 0
    30 mmap(0x7fb674cbe000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x14000) = 0x7fb674cbe000
    31 close(3)                                = 0
    32 open("/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
    33 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200m\0\0\0\0\0\0"..., 832) = 832
    34 fstat(3, {st_mode=S_IFREG|0755, st_size=142144, ...}) = 0
    35 mmap(NULL, 2208904, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb67488e000
    36 mprotect(0x7fb6748a5000, 2093056, PROT_NONE) = 0
    37 mmap(0x7fb674aa4000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16000) = 0x7fb674aa4000
    38 mmap(0x7fb674aa6000, 13448, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb674aa6000
    39 close(3)                                = 0
    40 open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
    41 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`&\2\0\0\0\0\0"..., 832) = 832
    42 fstat(3, {st_mode=S_IFREG|0755, st_size=2156352, ...}) = 0
    43 mmap(NULL, 3985920, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb6744c0000
    44 mprotect(0x7fb674684000, 2093056, PROT_NONE) = 0
    45 mmap(0x7fb674883000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c3000) = 0x7fb674883000
    46 mmap(0x7fb674889000, 16896, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb674889000
    47 close(3)                                = 0
    48 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6754e1000
    49 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6754df000
    50 arch_prctl(ARCH_SET_FS, 0x7fb6754df740) = 0
    51 mprotect(0x7fb674883000, 16384, PROT_READ) = 0
    52 mprotect(0x7fb674aa4000, 4096, PROT_READ) = 0
    53 mprotect(0x7fb674cbe000, 4096, PROT_READ) = 0
    54 mprotect(0x7fb674fc0000, 4096, PROT_READ) = 0
    55 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6754de000
    56 mprotect(0x7fb6752ab000, 32768, PROT_READ) = 0
    57 mprotect(0x604000, 4096, PROT_READ)     = 0
    58 mprotect(0x7fb6754eb000, 4096, PROT_READ) = 0
    59 munmap(0x7fb6754e3000, 27766)           = 0
    60 set_tid_address(0x7fb6754dfa10)         = 8478
    61 set_robust_list(0x7fb6754dfa20, 24)     = 0
    62 rt_sigaction(SIGRTMIN, {sa_handler=0x7fb674894860, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7fb67489d630}, NULL, 8) = 0
    63 rt_sigaction(SIGRT_1, {sa_handler=0x7fb6748948f0, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, sa_restorer=0x7fb67489d630}, NULL, 8) = 0
    64 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
    65 getrlimit(RLIMIT_STACK, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
    66 futex(0x7fb6752c796c, FUTEX_WAKE_PRIVATE, 2147483647) = 0
    67 futex(0x7fb6752c7978, FUTEX_WAKE_PRIVATE, 2147483647) = 0
    68 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
    69 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6754e9000
    70 write(1, "main 140421628819264\n", 21)  = 21
    71 brk(NULL)                               = 0x13c7000
    72 brk(0x13e8000)                          = 0x13e8000
    73 brk(NULL)                               = 0x13e8000
    74 mmap(NULL, 8392704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7fb673cbf000
    75 mprotect(0x7fb673cbf000, 4096, PROT_NONE) = 0
    76 clone(child_stack=0x7fb6744befb0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fb6744bf9d0, tls=0x7fb6744bf700, child_tidptr=0x7fb6744bf9d0) = 8479
    77 write(1, "main 140421628819264 sleep\n", 27) = 27
    78 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
    79 rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
    80 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
    81 nanosleep({tv_sec=3, tv_nsec=0}, 0x7ffcb46aec30) = 0
    82 futex(0x605364, FUTEX_CMP_REQUEUE_PRIVATE, 1, 2147483647, 0x605320, 2) = 1
    83 rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
    84 rt_sigaction(SIGCHLD, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
    85 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
    86 nanosleep({tv_sec=3, tv_nsec=0}, 0x7ffcb46aec30) = 0
    87 write(1, "main 140421628819264 end\n", 25) = 25
    88 exit_group(0)                           = ?
    89 +++ exited with 0 +++

    8479:

    1 set_robust_list(0x7fb6744bf9e0, 24)     = 0
    2 write(1, "140421611910912 wait\n", 21)  = 21
    3 futex(0x605364, FUTEX_WAIT_PRIVATE, 1, NULL) = 0
    4 write(1, "140421611910912 end wait\n", 25) = 25
    5 futex(0x605320, FUTEX_WAKE_PRIVATE, 1)  = 0
    6 madvise(0x7fb673cbf000, 8368128, MADV_DONTNEED) = 0
    7 exit(0)                                 = ?
    8 +++ exited with 0 +++

    主要分析:

    (1)8478 76行通过clone 函数创建一个子进程

    (2)8478主线程 81 行调用nanosleep 休眠函数自己进入休眠状态

    (3) 8479 第3行调用 futex 加锁, 传递参数 FUTEX_WAIT_PRIVATE 

    (4) 8479 第5行调用 futex 进入阻塞状态, 传递参数 FUTEX_WAKE_PRIVATE

    (5) 8478 第83行调用futex, 传递参数 FUTEX_CMP_REQUEUE_PRIVATE 唤醒阻塞的线程

    查看futex 相关操作如下:(相关的参数可以对应到去掉_PRIVATE 查看相关语义)

    [root@bogon ctest]# man 2 futex
    FUTEX(2)                                    Linux Programmer's Manual                                    FUTEX(2)
    
    NAME
           futex - fast user-space locking
    
    SYNOPSIS
           #include <linux/futex.h>
           #include <sys/time.h>
    
           int futex(int *uaddr, int op, int val, const struct timespec *timeout,
                     int *uaddr2, int val3);
    DESCRIPTION
           The  futex() system call provides a method for a program to wait for a value at a given address to change,
           and a method to wake up anyone waiting on a particular address (while the addresses for the same memory in
           separate  processes may not be equal, the kernel maps them internally so the same memory mapped in differ‐
           ent locations will correspond for futex() calls).  This system call is typically  used  to  implement  the
           contended case of a lock in shared memory, as described in futex(7).
    
           When  a futex(7) operation did not finish uncontended in user space, a call needs to be made to the kernel
           to arbitrate.  Arbitration can either mean putting the calling process to sleep or, conversely,  waking  a
           waiting process.
    
           Callers  of this function are expected to adhere to the semantics as set out in futex(7).  As these seman‐
           tics involve writing nonportable assembly instructions, this in turn probably means that most  users  will
           in fact be library authors and not general application developers.
    
           The  uaddr  argument needs to point to an aligned integer which stores the counter.  The operation to exe‐
           cute is passed via the op argument, along with a value val.
    
           Five operations are currently defined:
           FUTEX_WAIT
                  This operation atomically verifies that the futex address uaddr still contains the value  val,  and
                  sleeps  awaiting  FUTEX_WAKE  on this futex address.  If the timeout argument is non-NULL, its con‐
                  tents describe the minimum duration of the wait, which is infinite otherwise.  The arguments uaddr2
                  and val3 are ignored.
    
                  For  futex(7),  this  call  is executed if decrementing the count gave a negative value (indicating
                  contention), and will sleep until another process releases the futex and  executes  the  FUTEX_WAKE
                  operation.
    
           FUTEX_WAKE
                  This operation wakes at most val processes waiting on this futex address (i.e., inside FUTEX_WAIT).
                  The arguments timeout, uaddr2 and val3 are ignored.
    
                  For futex(7), this is executed if incrementing the count showed that there were waiters,  once  the
                  futex value has been set to 1 (indicating that it is available).
    
           FUTEX_FD (present up to and including Linux 2.6.25)
                  To  support  asynchronous  wakeups,  this  operation associates a file descriptor with a futex.  If
                  another process executes a FUTEX_WAKE, the process will receive the signal number that  was  passed
                  in  val.   The  calling  process  must close the returned file descriptor after use.  The arguments
                  timeout, uaddr2 and val3 are ignored.
    
                  To prevent race conditions, the caller should test if the  futex  has  been  upped  after  FUTEX_FD
                  returns.
    
                  Because it was inherently racy, FUTEX_FD has been removed from Linux 2.6.26 onward.
    
           FUTEX_REQUEUE (since Linux 2.5.70)
                  This  operation was introduced in order to avoid a "thundering herd" effect when FUTEX_WAKE is used
                  and all processes woken up need to acquire another futex.  This call wakes up  val  processes,  and
                  requeues  all  other  waiters  on  the futex at address uaddr2.  The arguments timeout and val3 are
                  ignored.
    
           FUTEX_CMP_REQUEUE (since Linux 2.6.7)
                  There was a race in the intended use of FUTEX_REQUEUE, so FUTEX_CMP_REQUEUE was  introduced.   This
                  is  similar  to FUTEX_REQUEUE, but first checks whether the location uaddr still contains the value
                  val3.  If not, the operation fails with the error EAGAIN.  The argument timeout is ignored.
    
    RETURN VALUE
           In the event of an error, all operations return -1, and set errno to indicate the error.  The return value
           on success depends on the operation, as described in the following list:
    
           FUTEX_WAIT
                  Returns 0 if the process was woken by a FUTEX_WAKE call.  See ERRORS for the various possible error
                  returns.
    
           FUTEX_WAKE
                  Returns the number of processes woken up.
    
           FUTEX_FD
                  Returns the new file descriptor associated with the futex.
    
           FUTEX_REQUEUE
                  Returns the number of processes woken up.
    
           FUTEX_CMP_REQUEUE
                  Returns the number of processes woken up.
    【当你用心写完每一篇博客之后,你会发现它比你用代码实现功能更有成就感!】
  • 相关阅读:
    VirtualXposed查看手机端网页及调试
    vue小toast插件报错runtine-only
    vuex的一个坑
    安卓4.4.4以下手机的兼容性问题
    WebForm(一)——IIS服务器、开发方式和简单基础
    winform窗体(六)——DataGridView控件及通过此控件中实现增删改查
    winform窗体(五)——布局方式
    winform(四)——简单计算器制作
    winform(三)——更换主窗体例子
    winform窗体(二)——控件
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/15584142.html
Copyright © 2020-2023  润新知