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.