Linux环境编程
1.__sync_fetch_and_add和__sync_bool_compare_and_swap
gcc從4.1.2提供了__sync_*系列的built-in函數(shù),用于提供加減和邏輯運(yùn)算的原子操作。
其聲明如下:
type __sync_fetch_and_add (type *ptr, type value, ...)
type __sync_fetch_and_sub (type *ptr, type value, ...)
type __sync_fetch_and_or (type *ptr, type value, ...)
type __sync_fetch_and_and (type *ptr, type value, ...)
type __sync_fetch_and_xor (type *ptr, type value, ...)
type __sync_fetch_and_nand (type *ptr, type value, ...)
type __sync_add_and_fetch (type *ptr, type value, ...)
type __sync_sub_and_fetch (type *ptr, type value, ...)
type __sync_or_and_fetch (type *ptr, type value, ...)
type __sync_and_and_fetch (type *ptr, type value, ...)
type __sync_xor_and_fetch (type *ptr, type value, ...)
type __sync_nand_and_fetch (type *ptr, type value, ...)
這兩組函數(shù)的區(qū)別在于第一組返回更新前的值,第二組返回更新后的值。
type可以是1,2,4或8字節(jié)長度的int類型,即:
int8_t / uint8_t
int16_t / uint16_t
int32_t / uint32_t
int64_t / uint64_t
后面的可擴(kuò)展參數(shù)(...)用來指出哪些變量需要memory barrier,因?yàn)槟壳癵cc實(shí)現(xiàn)的是full barrier(類似于linux kernel 中的mb(),表示這個操作之前的所有內(nèi)存操作不會被重排序到這個操作之后),所以可以略掉這個參數(shù)。
bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)
這兩個函數(shù)提供原子的比較和交換,如果*ptr == oldval,就將newval寫入*ptr,
第一個函數(shù)在相等并寫入的情況下返回true.
第二個函數(shù)在返回操作之前的值。
__sync_synchronize (...)發(fā)出一個full barrier.
關(guān)于memory barrier,cpu會對我們的指令進(jìn)行排序,一般說來會提高程序的效率,但有時(shí)候可能造成我們不希望得到的結(jié)果,舉一個例子,比如我們有一個硬件設(shè)備,它有4個寄存器,當(dāng)你發(fā)出一個操作指令的時(shí)候,一個寄存器存的是你的操作指令(比如READ),兩個寄存器存的是參數(shù)(比如是地址和size),最后一個寄存器是控制寄存器,在所有的參數(shù)都設(shè)置好之后向其發(fā)出指令,設(shè)備開始讀取參數(shù),執(zhí)行命令,程序可能如下:
write1(dev.register_size,size);
write1(dev.register_addr,addr);
write1(dev.register_cmd,READ);
write1(dev.register_control,GO);
如果最后一條write1被換到了前幾條語句之前,那么肯定不是我們所期望的,這時(shí)候我們可以在最后一條語句之前加入一個memory barrier,強(qiáng)制cpu執(zhí)行完前面的寫入以后再執(zhí)行最后一條:
write1(dev.register_size,size);
write1(dev.register_addr,addr);
write1(dev.register_cmd,READ);
__sync_synchronize();
write1(dev.register_control,GO);
memory barrier有幾種類型:
??? acquire barrier : 不允許將barrier之后的內(nèi)存讀取指令移到barrier之前(linux kernel中的wmb())。
??? release barrier : 不允許將barrier之前的內(nèi)存讀取指令移到barrier之后 (linux kernel中的rmb())。
??? full barrier??? : 以上兩種barrier的合集(linux kernel中的mb())。
還有兩個函數(shù):
type __sync_lock_test_and_set (type *ptr, type value, ...)
?? 將*ptr設(shè)為value并返回*ptr操作之前的值。
void __sync_lock_release (type *ptr, ...)
???? 將*ptr置0
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>static int count = 0;void *test_func(void *arg)
{int i=0;for(i=0;i<20000;++i){__sync_fetch_and_add(&count,1);}return NULL;
}int main(int argc, const char *argv[])
{pthread_t id[20];int i = 0;for(i=0;i<20;++i){pthread_create(&id[i],NULL,test_func,NULL);}for(i=0;i<20;++i){pthread_join(id[i],NULL);}printf("%d\n",count);return 0;
}
編譯# cc __sync_fetch_and_add.c
/tmp/ccse5ep7.o: In function `main':
__sync_fetch_and_add.c:(.text+0x86): undefined reference to `pthread_create'
__sync_fetch_and_add.c:(.text+0xb3): undefined reference to `pthread_join'
參考:http://www.linuxidc.com/Linux/2011-06/37403.htm
2.undefined reference to 'pthread_create'問題解決
pthread 庫不是 Linux 系統(tǒng)默認(rèn)的庫,連接時(shí)需要使用靜態(tài)庫 libpthread.a,所以在使用pthread_create()創(chuàng)建線程,以及調(diào)用 pthread_atfork()函數(shù)建立fork處理程序時(shí),需要鏈接該庫。
問題解決:在編譯中要加 -lpthread參數(shù)
重新編譯上述代碼#cc __sync_fetch_and_add.c -o add -lpthread
3.匯編中為什么會有NOP指令
1).”NOP"指令即空指令,nop并不是匯編指令,只是一條匯編偽指令,編譯器會將這條指令替換成像mov r7,r7之類的沒什么用處的操作,通常用于延時(shí)或等待。
2). 運(yùn)行該指令時(shí)單片機(jī)什么都不做,但是會占用一個指令的時(shí)間。也就是做精確延時(shí),這和for的延時(shí)程序比時(shí)間短,易控制。
3). 當(dāng)指令間需要有延時(shí)(給外部設(shè)備足夠的響應(yīng)時(shí)間;或是軟件的延時(shí)等),可以插入“NOP”指令。
4)就是通過nop指令的填充(nop指令一個字節(jié)),使指令按字對齊,從而減少取指令時(shí)的內(nèi)存訪問次數(shù)。(一般用來內(nèi)存地址偶數(shù)對齊,比如有一條指令,占3字節(jié),這時(shí)候使用nop指令,cpu?就可以從第四個字節(jié)處讀取指令了。)
5)通過nop指令產(chǎn)生一定的延遲,但是對于快速的CPU來說效果不明顯,可以使用rep前綴,多延遲幾個時(shí)鐘;-->具體應(yīng)該說是占用了3個時(shí)鐘脈沖!
6)i/o傳輸時(shí),也會用一下?nop,等待緩沖區(qū)清空,總線恢復(fù);
7)清除由上一個算術(shù)邏輯指令設(shè)置的flag位;
8).NOP通常在破解軟件時(shí)有特殊用途,例如檢查序列號,特定硬件或軟件需求,加密狗等的軟件。這是通過更改函數(shù)和/或子程序以跳過安全檢查,直接返回期望的檢測值實(shí)現(xiàn)的。由于大多數(shù)安全檢查子程序中的指令會被廢棄,它們會被NOP所代替。
更多參考:http://blog.csdn.net/erazy0/article/details/6071281??? http://zh.wikipedia.org/wiki/NOP
4.__asm__?("pause"?)和__asm__?("nop"?)
_asm pause 的反匯編代碼如下
00401480 . F2: prefix repne:
00401481 . 90 nop
00401482 . C3 retn
__asm nop 的反匯編代碼也如下
00401481 . 90 nop
00401482 . C3 retn
1).pause的編碼如上,是NOP加F3前綴,這條指令是為支持超線程的CPU做優(yōu)化用的,不支持超線程的CPU也能用,具體看INTEL手冊。
2).asm("NOP");是匯編語言,執(zhí)行空操作。通過一定次數(shù)的空操作達(dá)到延時(shí)的目的。具體次數(shù)通常經(jīng)過測試獲得。
參考:http://bbs.pediy.com/archive/index.php?t-88477.html
1.pause指令提升了自旋等待循環(huán)(spin-wait loop)的性能。當(dāng)執(zhí)行一個循環(huán)等待時(shí),Intel P4或Intel Xeon處理器會因?yàn)闄z測到一個可能的內(nèi)存順序違規(guī)(memory order violation)而在退出循環(huán)時(shí)使性能大幅下降。PAUSE指令給處理器提了個醒:這段代碼序列是個循環(huán)等待。處理器利用這個提示可以避免在大多數(shù)情況下的內(nèi)存順序違規(guī),這將大幅提升性能。因?yàn)檫@個原因,所以推薦在循環(huán)等待中使用PAUSE指令。
2.pause的另一個功能就是降低Intel P4在執(zhí)行循環(huán)等待時(shí)的耗電量。Intel P4處理器在循環(huán)等待時(shí)會執(zhí)行得非常快,這將導(dǎo)致處理器消耗大量的電力,而在循環(huán)中插入一個pause指令會大幅降低處理器的電力消耗。
3.pause指令雖然是在Intel P4處理器開始出現(xiàn)的,但是它可以向后與所有的IA32處理器兼容。在早期的IA32 CPU中,pause就像NOP指令。Intel P4和Intel Xeon處理器將pause實(shí)現(xiàn)成一個預(yù)定義的延遲(pre-defined delay)。這種延遲是有限的,而且一些處理器可以為0。pause指令不改變處理器的架構(gòu)狀態(tài)(也就是說,它實(shí)際上只是執(zhí)行了一個延遲——并不做任何其他事情——的操作)。
參考:http://blog.csdn.net/kofshower/article/details/7432612
5.按8字節(jié)對齊
希望malloc分配的數(shù)據(jù)區(qū)是按8字節(jié)對齊,所以在size不為8的倍數(shù)時(shí),我們需要將size調(diào)整為大于size的最小的8的倍數(shù)
size_t align8(size_t s) {
?? ?if(s & 0x7 == 0)
?? ??? ?return s;
?? ?return ((s >> 3) + 1) << 3;
}
參考:http://blog.codinglabs.org/articles/a-malloc-tutorial.html
6.大小寫字符轉(zhuǎn)換
#define ngx_tolower(c)????? (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
#define ngx_toupper(c)????? (u_char) ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c)
參考:http://blog.csdn.net/21aspnet/article/details/41251915
7.多線程和原子操作
原子操作就是執(zhí)行時(shí)不會被中斷的指令。
兩個原子操作不可能同時(shí)作用于同一個變量,這個是原子操作的一個保證,至于處理器或者操作系統(tǒng)如何實(shí)現(xiàn)那是另外一回事。
原子操作是指某些操作的不可中斷。分為bitops和atomic_t兩類,bitops用于標(biāo)志的設(shè)置;而atomic_t用于原子性的加減之類的運(yùn)算。
在原子操作中運(yùn)用了很多的volatile聲明。這樣系統(tǒng)會阻止編譯器對volatile聲明的變量進(jìn)行優(yōu)化,確保變量使用用戶定義的精確地址,而不是使用有著同一信息的別名。
參考:
http://blog.sina.com.cn/s/blog_6237dcca0100fjgl.html
http://www.cppblog.com/woaidongmao/archive/2009/10/19/98965.html
http://preshing.com/20130618/atomic-vs-non-atomic-operations/
http://hedengcheng.com/?p=803#more-803
8.負(fù)數(shù)變正數(shù)
負(fù)數(shù)&0x7fffffff???? -1&0x7fffffff=2147483647???? -2&0x7fffffff=2147483646 ?
???? -1的二進(jìn)制是1111 1111 1111 1111? 1111 1111 1111 1111
?2147483647是0111 1111 1111 1111? 1111 1111 1111 1111?? 用+N標(biāo)記
-2147483648是1000 0000 0000 0000 0000 0000 0000 0000 用 -N標(biāo)記
+N +1溢出=-N ?
最大正數(shù)溢出就是-1,0對應(yīng)最小負(fù)數(shù) ,見上圖。
總結(jié)
- 上一篇: 在Eclipse中使用Maven构建Sp
- 下一篇: Thift安装