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.

 

posted @ 2021-11-21 14:10  QiaoZhi  阅读(1210)  评论(0编辑  收藏  举报