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.