在使用pthread進行NDK中的多線程開發時,自己寫了一個BUG, 這個是啟動函數,即相當於Java中的Thread的run方法。初一看沒啥問題,編譯也能過,APP也能跑,但是每次都會crash。我把crash線程的log貼出來如下: 從log中看出,是記憶體訪問錯誤,然後使用addr2line工具 ...
在使用pthread進行NDK中的多線程開發時,自己寫了一個BUG,
1 void *darkGrayThread(void *args) 2 { 3 ThreadParam *param = (ThreadParam *)args; 4 LOG("start%d end%d ", param->start, param->end); 5 int end = param->end; 6 for(int i = param->start, j = i * 4; i < end; ++i, j+=4) 7 { 8 LOG("d1"); 9 param->r[i] = param->rgba[j]; 10 param->g[i] = param->rgba[j + 1]; 11 param->b[i] = param->rgba[j + 2]; 12 LOG("d2 %d end%d", i, param->end); 13 param->dark[i] = MINT(param->rgba[j], param->rgba[j + 1], param->rgba[j + 2]); 14 param->gray[i] = (UCHAR)((param->rgba[j] * 1224 + param->rgba[j + 1] * 2404 +param->rgba[j + 2] * 467) >> 12); 15 LOG("d3"); 16 } 17 }
這個是啟動函數,即相當於Java中的Thread的run方法。初一看沒啥問題,編譯也能過,APP也能跑,但是每次都會crash。我把crash線程的log貼出來如下:
1 04-16 14:28:31.577 27602 28062 D MyJni : d2 2087309 end2073600 2 04-16 14:28:31.637 27602 28062 D MyJni : d3 3 04-16 14:28:31.641 27602 28062 D MyJni : d3 4 04-16 14:28:31.641 27602 28062 D MyJni : d1 5 04-16 14:28:31.641 27602 28062 D MyJni : d2 2087552 end2073600 6 04-16 14:28:31.642 27602 28062 D MyJni : d3 7 04-16 14:28:31.642 27602 28062 D MyJni : d1 8 04-16 14:28:31.642 27602 28062 D MyJni : d1 9 04-16 14:28:31.642 27602 28062 D MyJni : d2 2087567 end2073600 10 04-16 14:28:31.642 27602 28062 D MyJni : d3 11 04-16 14:28:31.642 27602 28062 D MyJni : d3 12 04-16 14:28:31.785 27602 28062 D MyJni : d2 2089380 end2073600 13 04-16 14:28:31.785 27602 28062 D MyJni : d3 14 04-16 14:28:31.785 27602 28062 D MyJni : d1 15 04-16 14:28:31.786 27602 28062 D MyJni : d1 16 04-16 14:28:31.786 27602 28062 D MyJni : d2 2089401 end2073600 17 04-16 14:28:31.786 27602 28062 D MyJni : d2 2089402 end2073600 18 04-16 14:28:31.786 27602 28062 D MyJni : d3 19 04-16 14:28:31.786 27602 28062 D MyJni : d2 2089404 end2073600 20 04-16 14:28:32.339 27602 28062 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0xc6800000 in tid 28062 (Thread-4) 21 04-16 14:28:32.339 27602 28062 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0xc6800000 in tid 28062 (Thread-4) 22 04-16 14:28:32.340 454 454 W : debuggerd: handling request: pid=27602 uid=10129 gid=10129 tid=28062 23 04-16 14:28:32.381 28088 28088 F DEBUG : pid: 27602, tid: 28062, name: Thread-4 >>> com.willhua.opencvstudy <<< 24 04-16 14:28:32.381 28088 28088 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc6800000 25 04-16 14:28:32.381 28088 28088 F DEBUG : r0 000000a7 r1 c6600000 r2 cac6ef0e r3 000000be 26 04-16 14:28:32.381 28088 28088 F DEBUG : r4 caa4ca9c r5 00200000 r6 00000964 r7 c62038f8 27 04-16 14:28:32.381 28088 28088 F DEBUG : r8 00800002 r9 000001d3 sl cac6ef0e fp cac6ebe0 28 04-16 14:28:32.381 28088 28088 F DEBUG : ip c7680000 sp c62038e8 lr caa8e93f pc caa8e99a cpsr 200f0030 29 04-16 14:28:32.383 28088 28088 F DEBUG : 30 04-16 14:28:32.383 28088 28088 F DEBUG : backtrace: 31 04-16 14:28:32.383 28088 28088 F DEBUG : #00 pc 0004099a /data/app/com.willhua.opencvstudy-2/lib/arm/libOpenCV.so (_Z14darkGrayThreadPv+209) 32 04-16 14:28:32.383 28088 28088 F DEBUG : #01 pc 000475d3 /system/lib/libc.so (_ZL15__pthread_startPv+22) 33 04-16 14:28:32.383 28088 28088 F DEBUG : #02 pc 00019d3d /system/lib/libc.so (__start_thread+6)
從log中看出,是記憶體訪問錯誤,然後使用addr2line工具定位到是上述代碼中的第13行。
再仔細一點可以看到,log中列印的end都比前面的數字小!!!上面不是有for迴圈的條件語句嗎?怎麼會出現這種情況!?其中的MINT只是我使用define定義的求三個數中的最小數的巨集。
為了確定問題,我把13寫成了
1 UCHAR uu = MINT(param->rgba[j], param->rgba[j + 1], param->rgba[j + 2]); 2 param->dark[i] = uu;
然後根據log分析,還是param->dark[i] = uu; 這行報錯。然後我又跑去前面的代碼確定給dark分配的記憶體沒有問題。還是沒找到原因。
後面突然發現,寫的darkGrayThread沒有寫返回值!於是趕緊再後面添加一句return (void *)0; 再測試,發現沒問題,原因就是這個了。
為了知道原因,我在沒有寫return的版本的最後添加LOG("endend"); 發現每次都會有數量不等的endend日誌列印出來。這說明for的條件語句還是有退出迴圈的作用的。
要想繼續分析,可能需要對比有沒有return的兩個版本的彙編代碼,來比較一下有沒有return他們翻譯成彙編的區別,待後續分析。
這個問題的收穫就是:寫啟動程式一定記得有return語句,即使你的return值沒有用!