C_and_CPP 板


LINE

process 同步机制有 spinlock, mutex, semaphore, 我的学习方式是简化再简化, 然後 用程式码实作他们, 否则我只会有「名词」上的理解, 而不会真的理解。有了 spinlock 就有了基本的 process 同步机制。 以下的参考资料帮助我完成这个实作: Linux核同步机制之(一):原子操作 ( http://goo.gl/Z9PJOC ) Linux核同步机制之(四):spin lock ( http://goo.gl/AHTbku ) Linux解:基于最新的Linux4.0核 ( http://goo.gl/D9Ni5h ) p164 代码清单 7.1, 以及 第七章, 这部份把容易搞混的 memory barrier, compiler/cpu 的乱序执行做了一个很好 的说明。 由於要分解这些功能并简化他们, 通常我会设计简单的测试方式并辅以实作的小程式来理 解他们, spinlock 的测试让我大伤脑筋, 之前的想法是要先实作 process switch, 才能 测试 spinlock, 我也的确做了某些成果, 不过在我愈来愈会设计这些小实验後, 已经变 得很擅长这件事情。我想到一个更好的方法, 不用先实作 process switch, 我在 rpi2 写个 pthread 程式, 然後呼叫我自己写的 my_spin_lock, my_spin_unlock 取代 pthread_spin_lock, pthread_spin_unlock, 若行为一样, 就代表我成功了。 spinlock.c 1 #include "spinlock.h" 2 3 #include <stdio.h> 4 37 38 void spinlock_init(Spinlock *spinlock) 39 { 40 spinlock->val_ = 0; 41 } 42 43 int spin_lock(Spinlock *spinlock) 44 { 77 #if 0 78 lock_mutex: 79 if(spinlock->val_ == 1) 80 goto lock_mutex; 81 else 82 spinlock->val_ = 1; 83 84 #endif 103 unsigned long tmp; 104 int result; 105 106 __asm__ __volatile__("@ atomic_add\n" 107 "1: ldrex %0, [%3]\n" 108 " cmp %0, #1\n" 109 "beq 1b\n" 110 "mov %0, #1\n" 111 " strex %1, %0, [%3]\n" 112 " teq %1, #0\n" 113 " bne 1b" 114 : "=&r" (result), "=&r" (tmp), "+Qo"(spinlock->val_) 115 : "r" (&spinlock->val_) 116 : "cc"); 118 } 119 120 int spin_unlock(Spinlock *spinlock) 121 { 122 spinlock->val_ = 0; 123 } 124 125 #ifdef TEST 126 #include <pthread.h> 127 #include <signal.h> 128 129 FILE *fs; 130 Spinlock sp; 131 pthread_spinlock_t spinlock; 132 133 int run=1; 134 135 void* write_file_1(void *p) 136 { 137 int time=0; 138 pthread_t tid = pthread_self(); 139 140 while(run) 141 { 142 #ifdef PTHREAD_FUNC 143 pthread_spin_lock(&spinlock); 144 #else 145 spin_lock(&sp); 146 #endif 147 //printf("111\n"); 148 fprintf(fs, "%d ## thread 1 ## %d\n", time, tid); 149 fprintf(fs, "%d ## thread 11\n", time); 150 fprintf(fs, "%d ## thread 111\n", time); 151 #if 1 152 #ifdef PTHREAD_FUNC 153 pthread_spin_unlock(&spinlock); 154 #else 155 spin_unlock(&sp); 156 #endif 157 #endif 158 ++time; 159 } 160 // printf("thread 1 exit\n"); 161 } 162 163 void* write_file_2(void *p) 164 { 165 int time = 0; 166 pthread_t tid = pthread_self(); 167 168 while(run) 169 { 170 #ifdef PTHREAD_FUNC 171 pthread_spin_lock(&spinlock); 172 #else 173 spin_lock(&sp); 174 #endif 175 //printf("222\n"); 176 fprintf(fs, "%d ## thread 2 long string 0123456789 ## %d\n", time, tid); 177 fprintf(fs, "%d ## thread 22 long string 0123456789\n", time); 178 fprintf(fs, "%d ## thread 222 long string 0123456789\n", time); 179 #ifdef PTHREAD_FUNC 180 pthread_spin_unlock(&spinlock); 181 #else 182 spin_unlock(&sp); 183 #endif 184 ++time; 185 } 186 // printf("thread 2 exit\n"); 187 } 188 189 void* write_file_3(void *p) 190 { 191 int time = 0; 192 pthread_t tid = pthread_self(); 193 int i; 194 195 while(run) 196 { 197 #ifdef PTHREAD_FUNC 198 pthread_spin_lock(&spinlock); 199 #else 200 spin_lock(&sp); 201 #endif 202 fprintf(fs, "%d ## thread 3 long string ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()~ ## %d\n", time, tid); 203 fprintf(fs, "%d ## thread 33 long string ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()~\n", time); 204 fprintf(fs, "%d ## thread 333 long string ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()~\n", time); 205 #ifdef PTHREAD_FUNC 206 pthread_spin_unlock(&spinlock); 207 #else 208 spin_unlock(&sp); 209 #endif 210 ++time; 211 } 212 // printf("thread 2 exit\n"); 213 } 214 215 static void* sig_thread (void *arg) 216 { 217 sigset_t *set = arg; 218 int s, sig; 219 220 printf("sig thread pid: %d\n", getpid()); 221 222 for (;;) 223 { 224 s = sigwait (set, &sig); 225 if (s == 0) 226 { 227 printf ("Signal handling thread got signal %d\n", sig); 228 if (sig == SIGINT) 229 { 230 run = 0; 231 //break; 232 } 233 } 234 } 235 } 236 237 int ret1, ret2, ret3; 238 239 int main(int argc, char *argv[]) 240 { 241 pthread_t thread0, thread1, thread2, thread; 242 sigset_t set; 243 244 #ifdef PTHREAD_FUNC 245 pthread_spin_init(&spinlock, 0); 246 printf("init pthread spinlock\n"); 247 #else 248 spinlock_init(&sp); 249 printf("init my spinlock\n"); 250 #endif 251 252 sigemptyset (&set); 253 sigaddset (&set, SIGQUIT); 254 sigaddset (&set, SIGINT); 255 int s = pthread_sigmask (SIG_BLOCK, &set, NULL); 256 if (s != 0) 257 { 258 perror("pthread_sigmask"); 259 return -1; 260 } 261 262 263 printf("open %s to write\n", FN); 264 fs = fopen(FN, "w"); 265 if (fs == NULL) 266 { 267 perror("open fail"); 268 return -1; 269 } 270 271 pthread_create (&thread, NULL, &sig_thread, (void *) &set); 272 pthread_create(&thread0, NULL, write_file_1, NULL); 273 pthread_create(&thread1, NULL, write_file_2, NULL); 274 pthread_create(&thread2, NULL, write_file_3, NULL); 275 276 pthread_join(thread0, (void **)&ret1); 277 pthread_join(thread1, (void **)&ret2); 278 pthread_join(thread2, (void **)&ret3); 279 280 fclose(fs); 281 printf("test end\n"); 282 283 return 0; 284 } 285 #endif spinlock.c L77 ~ 84 是 c 版本的演算法, 为什麽不能用这个版本, 因为需要 atomic 操作, 这大家都知道, 不多说了; 困难的是怎麽实作 atomic, spinlock.c L103 ~ 116 是我参考 linux 3.10.37 arch/arm/include/asm/atomic.h atomic_add 改出来的 (因为 我自己写的都有问题 ... 冏), 这 inline assembly 实在太难, 我没能完全看懂, ldrex/strex 可以在 armv6, cortex armv7-A 上使用, 我在 rpi2 执行这个测试, 这个 版本应该也可以在 cortex m3 上执行, 这才是我真正的目的。 x86 可参考 arch/x86/include/asm/atomic.h 来实作。 arch/arm/include/asm/atomic.h 1 /* 2 * arch/arm/include/asm/atomic.h 3 * 4 * Copyright (C) 1996 Russell King. 5 * Copyright (C) 2002 Deep Blue Solutions Ltd. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 #ifndef __ASM_ARM_ATOMIC_H 12 #define __ASM_ARM_ATOMIC_H 13 14 #include <linux/compiler.h> 15 #include <linux/types.h> 16 #include <linux/irqflags.h> 17 #include <asm/barrier.h> 18 #include <asm/cmpxchg.h> 19 20 #define ATOMIC_INIT(i) { (i) } 21 22 #ifdef __KERNEL__ 23 24 /* 25 * On ARM, ordinary assignment (str instruction) doesn't clear the local 26 * strex/ldrex monitor on some implementations. The reason we can use it for 27 * atomic_set() is the clrex or dummy strex done on every exception return. 28 */ 29 #define atomic_read(v) (*(volatile int *)&(v)->counter) 30 #define atomic_set(v,i) (((v)->counter) = (i)) 31 32 #if __LINUX_ARM_ARCH__ >= 6 33 34 /* 35 * ARMv6 UP and SMP safe atomic ops. We use load exclusive and 36 * store exclusive to ensure that these are atomic. We may loop 37 * to ensure that the update happens. 38 */ 39 static inline void atomic_add(int i, atomic_t *v) 40 { 41 unsigned long tmp; 42 int result; 43 44 __asm__ __volatile__("@ atomic_add\n" 45 "1: ldrex %0, [%3]\n" 46 " add %0, %0, %4\n" 47 " strex %1, %0, [%3]\n" 48 " teq %1, #0\n" 49 " bne 1b" 50 : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) 51 : "r" (&v->counter), "Ir" (i) 52 : "cc"); 53 } 程式有 3 个 thread 在写同一个档案 /tmp/xyz1, 按下 ctrl-c 会收到 SIGINT, 程式会 正确的处理这个 SIGINT 然後结束整个程式 (这并不容易, 请参考《thread 和 signal ( http://goo.gl/9dKfjj )》)。spinlock test result 为失败与成功的内容。一开始的 实作并不正确, 所以我特别用了 pthread_spin_lock, pthread_spin_unlock 来测试, 发 现使用 pthread_spin_lock/pthread_spin_unlock 就会得到正确的结果。 spinlock test result 失败: 237 ## thread 1 ## 1985418336 237 ## thread 3 long string ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()~ ## 1968641120 206 ## thread 2 long string 0123456789 ## 1977029728 成功: 6 ## thread 1 ## 1985877088 6 ## thread 11 6 ## thread 111 0 ## thread 2 long string 0123456789 ## 1977488480 0 ## thread 22 long string 0123456789 0 ## thread 222 long string 0123456789 7 ## thread 1 ## 1985877088 7 ## thread 11 7 ## thread 111 1 ## thread 2 long string 0123456789 ## 1977488480 1 ## thread 22 long string 0123456789 1 ## thread 222 long string 0123456789 每个 thread 应该以 3 行为输出单位, 若是被混在一起, 表示虽然有某个 thread 取得 了 spinlock, 但其他的 thread 并没有 busy loop, 而是也取得了同样的 spinlock 并 进入了 critical section, 造成了失败的结果。 check_result.c 则是用来检查 /tmp/xyz1 是否是正确。整个测试在 rpi2 上完成。 不知道是不是还需要 memory barrier, dsb, isb, dmb 这些指令。验证 spinlock function 是否正确非常困难, 我也不确定这个版本一定是对的, 因为只要有一个失败案 例, 这个 spinlock 实作就不正确了, 若用上了有 bug 的 spinlock function, 那程式 会很难除错, 若核4 有这样的程式码应该会吓死不少程式人。 spinlock 做出来了, 那 mutex 呢? 把 spinlock.c L109 改成让出 cpu 的程式码就可以 了, 这就是俗称的去「睡觉」。你说要怎麽做? 这在 process switch 的阶段就已经会了 , 所以你得搞懂那个才行。 实作完 spinlock 後还有使用 spinlock 的议题, 非常的复杂, 感觉起来 mutex 是比较 好的, 那为什麽还要设计 spinlock, 又中断部份的程式码为什麽要 spinlock 而不用 mutex 呢? source code: https://github.com/descent/progs/tree/master/spinlock ( https://goo.gl/DMYSMX ) ref: 理解 Memory barrier (存屏障) ( http://goo.gl/EmxZYv ) Memory Barrier in Lock API ( http://goo.gl/xjrYyl ) Linux x86 spinlock 实现之分析 ( http://goo.gl/u1Csis ) 分析Linux中Spinlock在ARM及X86平台上的 ( http://goo.gl/g0tUQB ) DMB, DSB, ISB: http://www.07net01.com/linux/ARM_Cortex_M3_xuexibiji_4_5__14436_1347159341.html ( http://goo.gl/AbQwn0 ) http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0489c/CIHGHHIE.html ( http://goo.gl/ZyZNWD ) // 本文使用 Blog2BBS 自动将Blog文章转成缩址的BBS纯文字 http://goo.gl/TZ4E17 // blog 版本: http://descent-incoming.blogspot.tw/2015/11/spinlock-on-raspberry-pi-2.html --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 180.217.246.154
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1447594047.A.9E1.html
1F:推 winken2004: 推 11/15 22:08
2F:推 laladeer: 推 11/16 02:10
3F:推 ho83leo: 推 11/22 00:48







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:BuyTogether站内搜寻

TOP