volatileã¨atomicã®éã
volatileã¨atomicã®éãã調ã¹ãããã«ã以ä¸ã®C++ããã°ã©ã ãã³ã³ãã¤ã«ãã¦ã¿ãã
#include <atomic> void func1(int *p) { ++*p; ++*p; } void func2(volatile int *p) { ++*p; ++*p; } void func3(std::atomic_int *p) { ++*p; ++*p; }
$ g++ -std=c++11 -pthread -O2 -Wall -Wextra -g -c func.cpp -o func.o
ç°å¢ã«ããå¯è½æ§ã¯ããããåºåãããæ©æ¢°èªã¯ç«¯çã«è¨ãã¨æ¬¡ã®ãããªãã®ã«ãªãã(ãªãã¢ã¼ããã¯ãã£ã¯Linux x86-64)
func1: addl $2, (%rdi) ret func2: movl (%rdi), %eax addl $1, %eax movl %eax, (%rdi) movl (%rdi), %eax addl $1, %eax movl %eax, (%rdi) ret func3: lock addl $1, (%rdi) lock addl $1, (%rdi) ret
func1
ã¯ãã2ã足ããã¨ããåä½ããã¦ãããfunc2
ã¯ããã¡ã¢ãªããèªã¿è¾¼ãã§1ã足ãã¦æ¸ãè¾¼ããã¨ããåä½ã2åãã¦ãããfunc3
ã¯ããlock
ããªãã1ã足ããã¨ããåä½ã2åãã¦ããã
ããã¯ä»¥ä¸ã®éãã«ãã:
volatile
ã¯ãã¡ã¢ãªã®èªã¿è¾¼ã¿ãæ¸ãè¾¼ã¿ããå¯ä½ç¨ãä¼´ãåä½ã¨è¦ãªãã*1 ãã®ãããèªã¿è¾¼ã¿ãæ¸ãè¾¼ã¿åä½ãæ¸ããæé©åãè¡ããªãããã ããåæ°ãé çªããåã£ã¦ããã°ããã®ã§ãä»ã®ã¹ã¬ããã«å¹²æ¸ããããã©ããã¯èããªããatomic
ã¯ãä»ã®ã¹ã¬ãããåæã«èªã¿æ¸ããããã¨ãã¦ããããã²ã¨ã¾ã¨ã¾ãã®åä½ã®éã¯ç¬å çã«åä½ãããããªæ¯èãã«ãªããx86ã®å ´åã¯lock
ãã¬ãã£ãã¯ã¹ã§å®ç¾ã§ããã
åä½ç¢ºèª
ãã®åä½ã¯ä»¥ä¸ã®ããã°ã©ã ã§ç¢ºèªã§ããã
#include <cstdio> #include <atomic> #include <thread> void func1(int *p); void func2(volatile int *p); void func3(std::atomic_int *p); void count1(int *p) { for(int i = 0; i < 1000000; ++i) { func1(p); } } void count2(volatile int *p) { for(int i = 0; i < 1000000; ++i) { func2(p); } } void count3(std::atomic_int *p) { for(int i = 0; i < 1000000; ++i) { func3(p); } } int main(int argc, char *argv[]) { int num = -1; if(argc > 1) { std::sscanf(argv[1], "%d", &num); } if(num == 1) { int x = 0; std::thread th0(&count1, &x); std::thread th1(&count1, &x); th0.join(); th1.join(); std::printf("%d\n", x); } else if(num == 2) { volatile int x = 0; std::thread th0(&count2, &x); std::thread th1(&count2, &x); th0.join(); th1.join(); std::printf("%d\n", x); } else if(num == 3) { std::atomic_int x = ATOMIC_VAR_INIT(0); std::thread th0(&count3, &x); std::thread th1(&count3, &x); th0.join(); th1.join(); std::printf("%d\n", (int)x); } return 0; }
$ g++ -std=c++11 -pthread -O2 -Wall -Wextra -g -c main.cpp -o main.o $ g++ -std=c++11 -pthread -O2 -Wall -Wextra -g func.o main.o -o main
$ ./main 1 2497250 $ ./main 1 2432386 $ ./main 1 3136510 $ ./main 1 2411326 $ ./main 1 3466956 $ ./main 1 2367656 $ ./main 1 2297168
$ ./main 2 2324260 $ ./main 2 3137164 $ ./main 2 2374254 $ ./main 2 2627152 $ ./main 2 2593840 $ ./main 2 2871581 $ ./main 2 2218822 $ ./main 2 2617198
$ ./main 3 4000000 $ ./main 3 4000000 $ ./main 3 4000000 $ ./main 3 4000000 $ ./main 3 4000000 $ ./main 3 4000000 $ ./main 3 4000000
ããã¯ãã«ãã³ã¢ã®åä½çµæã«é¢ããã®ã§ç°å¢ã«ãã£ã¦ç°ãªãåä½ããããããããªããæå ã®ç°å¢ã¯VirtualBoxã§ä»®æ³åãããLinux x86-64ã§ãã£ãã
atomicã§ã¯ä¸ååãªå ´åããã
atomicã§ä¸ã¾ã¨ã¾ãã®åä½ã¨è¦ãªãããç¯å²ã¯ããå°ãããä¾ãã°*p
ãå¶æ°ã§ãã£ãã¨ããã¨ã以ä¸ã®é¢æ°ãç¹°ãè¿ãå®è¡ãã¦ã*p
ã®å¤ãå¤ãããªããã¨ãæå³ããã(ã·ã³ã°ã«ã¹ã¬ããã§ã¯ãããªã)ãããã«ãã¹ã¬ããã§ã¯ããã¯ãªããªãã
#include <atomic> void func(std:atomic_int *p) { *p += 1; *p ^= 1; }
ãã®ãããªå ´åã¯åã«*p
ãatomicã«ããã ãã§ã¯ä¸ååã ããmutexãªã©ã使ãã°ãã¾ãããã
*1:ããã¯ãã«ãã¹ã¬ããã®ããã®ä»çµã¿ã¨ããããããMemory-Mapped I/Oãªã©ã§ã¡ã¢ãªã®èªã¿æ¸ããåä½ãä¼´ãå ´åãæ³å®ããã¦ããã¨æãããã