### main函數(shù)執(zhí)行之前做了什么?(iOS)
&? dyld 是Apple 的動(dòng)態(tài)鏈接器贡定;在 xnu 內(nèi)核為程序啟動(dòng)做好準(zhǔn)備后绷跑,就會(huì)將 PC 控制權(quán)交給 dyld 負(fù)責(zé)剩下的工作 (dyld 是運(yùn)行在 用戶態(tài)的, 這里由 內(nèi)核態(tài) 切到了用戶態(tài))乎完。
1)dyld 開(kāi)始將程序二進(jìn)制文件初始化
2)交由ImageLoader 讀取 image辱揭,其中包含了我們的類(lèi)盾沫,方法等各種符號(hào)(Class、Protocol 闯传、Selector谨朝、 IMP)
3)由于runtime 向dyld 綁定了回調(diào),當(dāng)image加載到內(nèi)存后甥绿,dyld會(huì)通知runtime進(jìn)行處理
4)runtime 接手后調(diào)用map_images做解析和處理
5)接下來(lái)load_images 中調(diào)用call_load_methods方法字币,遍歷所有加載進(jìn)來(lái)的Class,按繼承層次依次調(diào)用Class的+load和其他Category的+load方法
6)至此 所有的信息都被加載到內(nèi)存中
7)最后dyld調(diào)用真正的main函數(shù)
注意:dyld會(huì)緩存上一次把信息加載內(nèi)存的緩存妹窖,所以第二次比第一次啟動(dòng)快一點(diǎn)
### KVO實(shí)現(xiàn)原理
1.KVO是基于runtime機(jī)制實(shí)現(xiàn)的
2.當(dāng)某個(gè)類(lèi)的屬性對(duì)象第一次被觀察時(shí)纬朝,系統(tǒng)就會(huì)在運(yùn)行期動(dòng)態(tài)地創(chuàng)建該類(lèi)的一個(gè)派生類(lèi),在這個(gè)派生類(lèi)中重寫(xiě)基類(lèi)中任何被觀察屬性的setter 方法骄呼。派生類(lèi)在被重寫(xiě)的setter方法內(nèi)實(shí)現(xiàn)真正的通知機(jī)制
3.如果原類(lèi)為Person共苛,那么生成的派生類(lèi)名為NSKVONotifying_Person
4.每個(gè)類(lèi)對(duì)象中都有一個(gè)isa指針指向當(dāng)前類(lèi)判没,當(dāng)一個(gè)類(lèi)對(duì)象的第一次被觀察,那么系統(tǒng)會(huì)偷偷將isa指針指向動(dòng)態(tài)生成的派生類(lèi)隅茎,從而在給被監(jiān)控屬性賦值時(shí)執(zhí)行的是派生類(lèi)的setter方法
5.鍵值觀察通知依賴(lài)于NSObject 的兩個(gè)方法: willChangeValueForKey: 和 didChangevlueForKey:澄峰;在一個(gè)被觀察屬性發(fā)生改變之前, willChangeValueForKey:一定會(huì)被調(diào)用辟犀,這就 會(huì)記錄舊的值俏竞。而當(dāng)改變發(fā)生后,didChangeValueForKey:會(huì)被調(diào)用堂竟,繼而 observeValueForKey:ofObject:change:context: 也會(huì)被調(diào)用魂毁。
### ASCII碼表的一般規(guī)律
& 16進(jìn)制的0x30到0x39表示數(shù)字0到數(shù)字9;
& 16進(jìn)制的0x61到0x7A表示小寫(xiě)字母a到z;
& 16進(jìn)制的0x41到0x5A表示大寫(xiě)字母A到Z;
記住: jpg的頭部是<ffd8ffe0>? png的頭部是<89504e47>
### TCP的幾種狀態(tài)
在TCP層,有個(gè)FLAGS字段出嘹,這個(gè)字段有以下幾個(gè)標(biāo)識(shí):SYN, FIN, ACK, PSH, RST, URG.
其中席楚,對(duì)于我們?nèi)粘5姆治鲇杏玫木褪乔懊娴奈鍌€(gè)字段。
它們的含義是:
SYN表示建立連接税稼,
FIN表示關(guān)閉連接烦秩,
ACK表示響應(yīng),
PSH表示有 DATA數(shù)據(jù)傳輸郎仆,
RST表示連接重置只祠。
### 信號(hào)量
dispatch_semaphore的使用場(chǎng)景是處理并發(fā)控制.
dispatch_semaphore_create => 創(chuàng)建一個(gè)信號(hào)量
dispatch_semaphore_signal => 發(fā)送一個(gè)信號(hào)
dispatch_semaphore_wait => 等待信號(hào)
& 系統(tǒng)中規(guī)定當(dāng)信號(hào)量值為0時(shí),必須等待扰肌,知道信號(hào)量值不為零才能繼續(xù)操作抛寝。?
我們的信號(hào)量也可以實(shí)現(xiàn)同樣的功能。 首先狡耻,創(chuàng)建一個(gè)信號(hào)量墩剖。 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 創(chuàng)建方法里會(huì)傳入一個(gè)long型的參數(shù),這個(gè)東西你可以想象是一個(gè)庫(kù)存夷狰。有了庫(kù)存才可以出貨岭皂。 dispatch_semaphore_wait,就是每運(yùn)行一次沼头,會(huì)先清一個(gè)庫(kù)存爷绘,如果庫(kù)存為0,那么根據(jù)傳入的等待時(shí)間进倍,決定等待增加庫(kù)存的時(shí)間土至,如果設(shè)置為DISPATCH_TIME_FOREVER,那么意思就是永久等待增加庫(kù)存,否則就永遠(yuǎn)不往下面走猾昆。
dispatch_semaphore_signal陶因,就是每運(yùn)行一次,增加一個(gè)庫(kù)存.
// 某個(gè)信號(hào)進(jìn)行等待垂蜗, timeout:等待時(shí)間楷扬,永遠(yuǎn)等待為 DISPATCH_TIME_FOREVER
dispatch_semaphore_wait(<#dispatch_semaphore_t dsema#>, <#dispatch_time_t timeout#>)
等待信號(hào)解幽,具體操作是首先判斷信號(hào)量desema是否大于0,如果大于0就減掉1個(gè)信號(hào)烘苹,往下執(zhí)行躲株;
如果等于0函數(shù)就阻塞該線程等待timeout(注意timeout類(lèi)型為dispatch_time_t)時(shí),其所處線程自動(dòng)執(zhí)行其后的語(yǔ)句镣衡。
### TCP連接的三次握手
第一次握手:客戶端發(fā)送syn包(syn=j)到服務(wù)器霜定,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn)廊鸥;
第二次握手:服務(wù)器收到syn包望浩,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包黍图,即SYN+ACK包曾雕,此時(shí)服務(wù)器進(jìn)入SYN+RECV狀態(tài)奴烙;
第三次握手:客戶端收到服務(wù)器的SYN+ACK包助被,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1),此發(fā)送完畢切诀,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài)揩环,完成三次狀態(tài)。
### 字典實(shí)現(xiàn)原理
一:字典原理
NSDictionary(字典)是使用hash表來(lái)實(shí)現(xiàn)key和value之間的映射和存儲(chǔ)的
方法:-?(void)setObject:(id)anObject?forKey:(id)aKey;
Objective-C中的字典N(xiāo)SDictionary底層其實(shí)是一個(gè)哈希表
二:哈希原理
散列表(Hash table幅虑,也叫哈希表)丰滑,是根據(jù)關(guān)鍵碼值(Key value)而直接進(jìn)行訪問(wèn)的數(shù)據(jù)結(jié)構(gòu)。也就是說(shuō)倒庵,它通過(guò)把關(guān)鍵碼值映射到表中一個(gè)位置來(lái)訪問(wèn)記錄褒墨,以加快查找的速度。這個(gè)映射函數(shù)叫做散列函數(shù)擎宝,存放記錄的數(shù)組叫做散列表郁妈。
給定表M,存在函數(shù)f(key)绍申,對(duì)任意給定的關(guān)鍵字值key噩咪,代入函數(shù)后若能得到包含該關(guān)鍵字的記錄在表中的地址,則稱(chēng)表M為哈希(Hash)表极阅,函數(shù)f(key)為哈希(Hash) 函數(shù)胃碾。
哈希概念:哈希表的本質(zhì)是一個(gè)數(shù)組,數(shù)組中每一個(gè)元素稱(chēng)為一個(gè)箱子(bin)筋搏,箱子中存放的是鍵值對(duì)仆百。
三:哈希存儲(chǔ)過(guò)程
1.根據(jù) key 計(jì)算出它的哈希值 h。
2.假設(shè)箱子的個(gè)數(shù)為 n奔脐,那么這個(gè)鍵值對(duì)應(yīng)該放在第 (h % n) 個(gè)箱子中俄周。
3.如果該箱子中已經(jīng)有了鍵值對(duì)栏账,就使用開(kāi)放尋址法或者拉鏈法解決沖突。
在使用拉鏈法解決哈希沖突時(shí)栈源,每個(gè)箱子其實(shí)是一個(gè)鏈表挡爵,屬于同一個(gè)箱子的所有鍵值對(duì)都會(huì)排列在鏈表中。
哈希表還有一個(gè)重要的屬性: 負(fù)載因子(load factor)甚垦,它用來(lái)衡量哈希表的空/滿程度茶鹃,一定程度上也可以體現(xiàn)查詢(xún)的效率,計(jì)算公式為:
負(fù)載因子 = 總鍵值對(duì)數(shù) / 箱子個(gè)數(shù)
負(fù)載因子越大艰亮,意味著哈希表越滿闭翩,越容易導(dǎo)致沖突,性能也就越低迄埃。因此疗韵,一般來(lái)說(shuō),當(dāng)負(fù)載因子大于某個(gè)常數(shù)(可能是 1侄非,或者 0.75 等)時(shí)蕉汪,哈希表將自動(dòng)擴(kuò)容。
哈希表在自動(dòng)擴(kuò)容時(shí)逞怨,一般會(huì)創(chuàng)建兩倍于原來(lái)個(gè)數(shù)的箱子者疤,因此即使 key 的哈希值不變,對(duì)箱子個(gè)數(shù)取余的結(jié)果也會(huì)發(fā)生改變叠赦,因此所有鍵值對(duì)的存放位置都有可能發(fā)生改變驹马,這個(gè)過(guò)程也稱(chēng)為重哈希(rehash)。
哈希表的擴(kuò)容并不總是能夠有效解決負(fù)載因子過(guò)大的問(wèn)題除秀。假設(shè)所有 key 的哈希值都一樣糯累,那么即使擴(kuò)容以后他們的位置也不會(huì)變化。雖然負(fù)載因子會(huì)降低册踩,但實(shí)際存儲(chǔ)在每個(gè)箱子中的鏈表長(zhǎng)度并不發(fā)生改變泳姐,因此也就不能提高哈希表的查詢(xún)性能。
基于以上總結(jié)棍好,細(xì)心的朋友可能會(huì)發(fā)現(xiàn)哈希表的兩個(gè)問(wèn)題:
1.如果哈希表中本來(lái)箱子就比較多仗岸,擴(kuò)容時(shí)需要重新哈希并移動(dòng)數(shù)據(jù),性能影響較大借笙。
2.如果哈希函數(shù)設(shè)計(jì)不合理扒怖,哈希表在極端情況下會(huì)變成線性表,性能極低业稼。
HashMap 的實(shí)例有兩個(gè)參數(shù)影響其性能:初始容量和加載因子盗痒。容量是哈希表中桶的數(shù)量,初始容量只是哈希表在創(chuàng)建時(shí)的容量。加載因子 是哈希表在其容量自動(dòng)增加之前可以達(dá)到多滿的一種尺度俯邓。當(dāng)哈希表中的條目數(shù)超出了加載因子與當(dāng)前容量的乘積時(shí)骡楼,則要對(duì)該哈希表進(jìn)行 rehash 操作(即重建內(nèi)部數(shù)據(jù)結(jié)構(gòu)),從而哈希表將具有大約兩倍的桶數(shù)稽鞭。
通常鸟整,默認(rèn)加載因子 (.75) 在時(shí)間和空間成本上尋求一種折衷。加載因子過(guò)高雖然減少了空間開(kāi)銷(xiāo)朦蕴,但同時(shí)也增加了查詢(xún)成本(在大多數(shù) HashMap 類(lèi)的操作中篮条,包括 get 和 put 操作眉菱,都反映了這一點(diǎn))俱笛。在設(shè)置初始容量時(shí)應(yīng)該考慮到映射中所需的條目數(shù)及其加載因子,以便最大限度地減少 rehash 操作次數(shù)商玫。如果初始容量大于最大條目數(shù)除以加載因子疹娶,則不會(huì)發(fā)生 rehash 操作伴栓。
很多人都有這個(gè)疑問(wèn),為什么hashmap的數(shù)組初始化大小都是2的次方大小時(shí)雨饺,hashmap的效率最高钳垮,我以2的4次方舉例,來(lái)解釋一下為什么數(shù)組大小為2的冪時(shí)hashmap訪問(wèn)的性能最高沛膳。本文主要描述了HashMap的結(jié)構(gòu)扔枫,和hashmap中hash函數(shù)的實(shí)現(xiàn),以及該實(shí)現(xiàn)的特性锹安,同時(shí)描述了hashmap中resize帶來(lái)性能消耗的根本原因,以及將普通的域模型對(duì)象作為key的基本要求倚舀。尤其是hash函數(shù)的實(shí)現(xiàn)叹哭,可以說(shuō)是整個(gè)HashMap的精髓所在,只有真正理解了這個(gè)hash函數(shù)痕貌,才可以說(shuō)對(duì)HashMap有了一定的理解风罩。
① hashmap是用鏈地址法進(jìn)行處理,多個(gè)key 對(duì)應(yīng)于表中的一個(gè)索引位置的時(shí)候進(jìn)行鏈地址處理舵稠,hashmap其實(shí)就是一個(gè)數(shù)組+鏈表的形式超升。
② 當(dāng)有多個(gè)key的值相同時(shí),hashmap中只保存具有相同key的一個(gè)節(jié)點(diǎn)哺徊,也就是說(shuō)相同key的節(jié)點(diǎn)會(huì)進(jìn)行覆蓋室琢。
③在hashmap中查找一個(gè)值,需要兩次定位落追,先找到元素在數(shù)組的位置的鏈表上盈滴,然后在鏈表上查找,在HashMap中的第一次定位是由hash值確定的轿钠,第二次定位由key和hash值確定巢钓。
④節(jié)點(diǎn)在找到所在的鏈后病苗,插入鏈中是采用的是頭插法,也就是新節(jié)點(diǎn)都插在鏈表的頭部症汹。
⑤在hashmap中上圖左邊綠色的數(shù)組中也存放元素硫朦,新節(jié)點(diǎn)都是放在左邊的table中的,這個(gè)在上圖中為了形象的表現(xiàn)鏈表形式而沒(méi)有使用背镇。
### 結(jié)構(gòu)體字節(jié)大小問(wèn)題
原則1:數(shù)據(jù)成員對(duì)齊規(guī)則:結(jié)構(gòu)(struct或聯(lián)合union)的數(shù)據(jù)成員阵幸,第一個(gè)數(shù)據(jù)成員放在offset為0的地方,
后面每個(gè)數(shù)據(jù)成員存儲(chǔ)的起始位置要從該成員(自身)大小的整數(shù)倍開(kāi)始(如int在32位機(jī)為4字節(jié)芽世,則要從4的整數(shù)倍地址開(kāi)始存儲(chǔ))挚赊。
原則2:結(jié)構(gòu)體作為成員:如果一個(gè)結(jié)構(gòu)里有某些結(jié)構(gòu)體成員,則結(jié)構(gòu)體成員要從其內(nèi)部最大元素大小的整數(shù)倍地址開(kāi)始存儲(chǔ)济瓢。
(struct a里存有struct b荠割,b里有char,int旺矾,double等元素蔑鹦,那b應(yīng)該從8的整數(shù)倍開(kāi)始存儲(chǔ)。)
原則3:計(jì)算工作:結(jié)構(gòu)體的總大小箕宙,也就是sizeof的結(jié)果嚎朽,必須是其內(nèi)部最大成員的整數(shù)倍,不足的要補(bǔ)齊柬帕。
例1:struct A{
???????????????????? int a;
???????????????????? double b;
???????????????????? float c;
??????????};
??????????????? struct B{
???????????????????? char e[2];
???????????????????? int f;
???????????????????? double g;
???????????????????? short h;
???????????????????? struct A i;
??????????????????? };
?????? sizeof(A) = 24; int為4哟忍,double為8,float為4陷寝,總長(zhǎng)為8的倍數(shù)锅很,補(bǔ)齊,所以整個(gè)A為24凤跑。
?????? sizeof(B) = 48;
### 函數(shù)execve
execve函數(shù)調(diào)用可以執(zhí)行一個(gè)指定的程序,但一旦執(zhí)行了execve函數(shù)之后,調(diào)用execve的進(jìn)程空間就被指定的程序
占據(jù)了.所以execve并不產(chǎn)生新的進(jìn)程,只是將進(jìn)程空間替換而已.
char *ss = {"a","123",NULL};//命令行參數(shù)
execve("a",ss,NULL);
### 函數(shù)wait
父進(jìn)程調(diào)用wait之后會(huì)阻塞,直到子進(jìn)程結(jié)束之后才返回,wait函數(shù)的參數(shù)就是子進(jìn)程的退出碼.
// fork后的父進(jìn)程和子進(jìn)程之間執(zhí)行是隨機(jī)的爆安,無(wú)序的,互相不干擾仔引,因?yàn)樗麄兪莾蓚€(gè)不同的進(jìn)程.
// 變量的地址為偏移地址扔仓,而不是絕對(duì)地址.首地址不一樣,修改變量不會(huì)影響另一個(gè)變量.
// 孤兒進(jìn)程:子進(jìn)程活著,父進(jìn)程死了咖耘,這個(gè)時(shí)候?qū)τ谧舆M(jìn)程來(lái)講父進(jìn)程就變成了init.
// 父進(jìn)程活著翘簇,子進(jìn)程死了,子進(jìn)程就成了僵死進(jìn)程鲤看,等父進(jìn)程收尸缘揪。父進(jìn)程退出的話,僵死的子進(jìn)程也就沒(méi)有了。
// 父進(jìn)程和子進(jìn)程會(huì)共享打開(kāi)的文件描述符.
### 函數(shù)fork
#include
pid_t fork(void);
// fork調(diào)用就是執(zhí)行自己,內(nèi)存中會(huì)出現(xiàn)一模一樣的兩個(gè)進(jìn)程
// fork執(zhí)行成功,向父進(jìn)程返回子進(jìn)程的pid,子進(jìn)程內(nèi)部執(zhí)行fork返回0<若返回0則說(shuō)明代碼運(yùn)行在子進(jìn)程上>
// fork創(chuàng)建的新進(jìn)程是和父進(jìn)程一樣的副本(除了pid不一樣)<變量int m會(huì)被克隆到子進(jìn)程的內(nèi)存空間,變量是兩份>
// 子進(jìn)程沒(méi)有繼承父進(jìn)程的超時(shí)設(shè)置,父進(jìn)程創(chuàng)建的文件鎖.
### 進(jìn)程和線程
進(jìn)程是一個(gè)正在執(zhí)行程序的實(shí)例.// 一個(gè)PID標(biāo)識(shí)一個(gè)進(jìn)程
程序----就是你磁盤(pán)上的那個(gè)文件而已,它是靜態(tài)的.
進(jìn)程----一旦這個(gè)程序備操作系統(tǒng)加載到內(nèi)存,開(kāi)始執(zhí)行了,那么他就是進(jìn)程
// 時(shí)間片模型
# 倒過(guò)來(lái)讀,就很容易理解聲明.
int *pt;//指向int型的指針
const int * pci;//指向const int的指針就是指向整數(shù)常量的指針
int* const p;// 指向int型變量的常量指針,指針地址不可修改.
void (*foo)(int num);//指向參數(shù)為int,返回值為void的函數(shù)的指針,函數(shù)指針
void *foo(int num);//返回值為指針的函數(shù)
int* arr[5];//指針數(shù)組,數(shù)組中每一個(gè)元素都是指針
int (*p)[10] ;// 數(shù)組指針,p指向的是一個(gè)帶10個(gè)int型元素的數(shù)組
### 編程高階
-(int)executeWithCommand:(NSString *)cmd {
NSLog(@"%@",cmd);
NSArray *cmds = [cmd componentsSeparatedByString:@" "];
int argc = (int)cmds.count;
char** argv = (char**)malloc(sizeof(char*)*argc);
for(int i = 0;i < argc; i++) {
? ? ? ?argv[i]=(char*)malloc(sizeof(char)*1024);
? ? ? ?strcpy(argv[i],[[cmds objectAtIndex:i] UTF8String]);
}
int ret = ycmagickmain(argc, argv);
for(int i=0;i < argc;i++){
? ? ? free(argv[i]);
? ? ? free(argv);
? ? ? return ret;
}
### 單鏈表 & 二叉樹(shù)
typedef struct ListElmt_ {
void *data;
struct ListElmt_ *next;
} ListElmt;
typedef struct BiTreeNode_ {
void *data;
struct BiTreeNode_ *left;
struct BiTreeNode_ *right;
} BiTreeNode;
### memset函數(shù)
void *memset(void *s, int ch, size_t n);
函數(shù)解釋?zhuān)簩中當(dāng)前位置后面的n個(gè)字節(jié) (typedef unsigned int size_t )用 ch 替換并返回 s 找筝。
memset:作用是在一段內(nèi)存塊中填充某個(gè)給定的值蹈垢,它是對(duì)較大的結(jié)構(gòu)體或數(shù)組進(jìn)行清零操作的一種最快方法
### memcpy函數(shù)
void *memcpy(void *dest, const void *src, size_t n);
從源src所指的內(nèi)存地址的起始位置開(kāi)始拷貝n個(gè)字節(jié)到目標(biāo)dest所指的內(nèi)存地址的起始位置中.
函數(shù)返回指向dest的指針.
### sprintf函數(shù)
功能 把格式化的數(shù)據(jù)寫(xiě)入某個(gè)字符串緩沖區(qū)。
原型 int sprintf( char *buffer, const char *format, [ argument] … );
參數(shù)列表
buffer:char型指針袖裕,指向?qū)⒁獙?xiě)入的字符串的緩沖區(qū)曹抬。
format:格式化字符串。
[argument]...:可選參數(shù)急鳄,可以是任何類(lèi)型的數(shù)據(jù)谤民。
返回寫(xiě)入buffer 的字符數(shù),出錯(cuò)則返回-1. 如果 buffer 或 format 是空指針疾宏,且不出錯(cuò)而繼續(xù)张足,函數(shù)將返回-1,并且 errno 會(huì)被設(shè)置為 EINVAL坎藐。
### 文件操作相關(guān)函數(shù)
函數(shù)原型:FILE * fopen(const char * path,const char * mode);
返回值:文件順利打開(kāi)后为牍,指向該流的文件指針就會(huì)被返回。如果文件打開(kāi)失敗則返回NULL岩馍,并把錯(cuò)誤代碼存在errno中碉咆。
一般而言,打開(kāi)文件后會(huì)做一些文件讀取或?qū)懭氲膭?dòng)作蛀恩,若打開(kāi)文件失敗疫铜,接下來(lái)的讀寫(xiě)動(dòng)作也無(wú)法順利進(jìn)行,所以一般在fopen()后作錯(cuò)誤判斷及處理双谆。
參數(shù)說(shuō)明:
參數(shù)path字符串包含欲打開(kāi)的文件路徑及文件名壳咕,參數(shù)mode字符串則代表著流形態(tài)。
mode有下列幾種形態(tài)字符串:
“r” 以只讀方式打開(kāi)文件佃乘,該文件必須存在囱井。
“r+” 以可讀寫(xiě)方式打開(kāi)文件,該文件必須存在趣避。
”rb+“ 讀寫(xiě)打開(kāi)一個(gè)二進(jìn)制文件,允許讀寫(xiě)數(shù)據(jù)新翎,文件必須存在程帕。
“w” 打開(kāi)只寫(xiě)文件,若文件存在則文件長(zhǎng)度清為0地啰,即該文件內(nèi)容會(huì)消失愁拭。若文件不存在則建立該文件。
“w+” 打開(kāi)可讀寫(xiě)文件亏吝,若文件存在則文件長(zhǎng)度清為零岭埠,即該文件內(nèi)容會(huì)消失。若文件不存在則建立該文件。
“a” 以附加的方式打開(kāi)只寫(xiě)文件惜论。若文件不存在许赃,則會(huì)建立該文件,如果文件存在馆类,寫(xiě)入的數(shù)據(jù)會(huì)被加到文件尾混聊,即文件原先的內(nèi)容會(huì)被保留。(EOF符保留)
”a+“ 以附加方式打開(kāi)可讀寫(xiě)的文件乾巧。若文件不存在句喜,則會(huì)建立該文件,如果文件存在沟于,寫(xiě)入的數(shù)據(jù)會(huì)被加到文件尾后咳胃,即文件原先的內(nèi)容會(huì)被保留。 (原來(lái)的EOF符不保留)
函數(shù)原型:int fclose( FILE *fp );
返回值:如果流成功關(guān)閉旷太,fclose 返回 0展懈,否則返回EOF(-1)。(如果流為NULL泳秀,而且程序可以繼續(xù)執(zhí)行标沪,fclose設(shè)定error number給EINVAL,并返回EOF嗜傅。)
函數(shù)原型 size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ;
buffer 用于接收數(shù)據(jù)的內(nèi)存地址
size 要讀的每個(gè)數(shù)據(jù)項(xiàng)的字節(jié)數(shù)金句,單位是字節(jié)
count 要讀count個(gè)數(shù)據(jù)項(xiàng),每個(gè)數(shù)據(jù)項(xiàng)size個(gè)字節(jié).
stream 輸入流
返回值
返回真實(shí)寫(xiě)入的項(xiàng)數(shù)吕嘀,若大于count則意味著產(chǎn)生了錯(cuò)誤违寞。另外,產(chǎn)生錯(cuò)誤后偶房,文件位置指示器是無(wú)法確定的趁曼。若其他stream或buffer為空指針,或在unicode模式中寫(xiě)入的字節(jié)數(shù)為奇數(shù)棕洋,此函數(shù)設(shè)置errno為EINVAL以及返回0.
size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
注意:這個(gè)函數(shù)以二進(jìn)制形式對(duì)文件進(jìn)行操作挡闰,不局限于文本文件
返回值:返回實(shí)際寫(xiě)入的數(shù)據(jù)塊數(shù)目
(1)buffer:是一個(gè)指針,對(duì)fwrite來(lái)說(shuō)掰盘,是要獲取數(shù)據(jù)的地址摄悯;
(2)size:要寫(xiě)入內(nèi)容的單字節(jié)數(shù);
(3)count:要進(jìn)行寫(xiě)入size字節(jié)的數(shù)據(jù)項(xiàng)的個(gè)數(shù)愧捕;
(4)stream:目標(biāo)文件指針奢驯;
(5)返回實(shí)際寫(xiě)入的數(shù)據(jù)項(xiàng)個(gè)數(shù)count。
int fseek(FILE *stream, long offset, int fromwhere);函數(shù)設(shè)置文件指針stream的位置次绘。
如果執(zhí)行成功瘪阁,stream將指向以fromwhere為基準(zhǔn)撒遣,偏移offset(指針偏移量)個(gè)字節(jié)的位置,函數(shù)返回0管跺。如果執(zhí)行失敗(比如offset超過(guò)文件自身大小)义黎,則不改變stream指向的位置,函數(shù)返回一個(gè)非0值伙菜。
/* 讀一個(gè)文件,open,close是系統(tǒng)函數(shù),fopen,fclose是庫(kù)函數(shù),建議用庫(kù)函數(shù) */
int fd = open("a.txt",O_RDONLY);
char buf[100] = {0};
while(read(fd,buf,sizeof(buf)-1) > 0)
{
printf("%s",buf);
memset(buf,0,sizeof(buf));
}
// 寫(xiě)文件
write(fd,buf,strlen(buf));
close(fd);//記得關(guān)閉文件
### 數(shù)據(jù)庫(kù)編程
1:)連接到數(shù)據(jù)庫(kù)
MYSQL *mysql_real_connect(MYSQL *pmvsql,const char* hostname,
const char* username,const char* passwd,const char* dbname,0,0,0);
//函數(shù)成功返回指向MySql連接的指針,失敗返回NULL
2:)執(zhí)行SQL語(yǔ)句的函數(shù)
int mysql_query(MYSQL* pmysql,const char* sql);
//成功返回0;
注: 編寫(xiě)mysql程序,連接到server之后,應(yīng)該執(zhí)行sql語(yǔ)句:SET NAMES utf8;
3:)獲取查詢(xún)結(jié)果
MYSQL_RES* mysql_store_result(MYSQL* pmysql);
// 成功返回一個(gè)查詢(xún)結(jié)果指針,查詢(xún)無(wú)結(jié)果或者錯(cuò)誤返回NULL
// 需調(diào)用mysql_free_result(MYSQL_RES *res) 來(lái)釋放相關(guān)資源.
4:)查看查詢(xún)結(jié)果
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
// MYSQL_ROW row相當(dāng)于一個(gè)一行數(shù)據(jù).
// row[0]表示第一列;
### mysql進(jìn)階
1:)查詢(xún)語(yǔ)句
select [ALL|DISTINCT]結(jié)果項(xiàng)列表 from子句 where子句 group子句 having子句 order子句 limit子句
// 上面子句的相對(duì)順序不能打亂,實(shí)際上,在其內(nèi)部計(jì)算的過(guò)程中,也是按此先后順序進(jìn)行的.
// [all | distinct] 顯示全部重復(fù)項(xiàng)(默認(rèn)) 或 消除重復(fù)項(xiàng)
// from 數(shù)據(jù)來(lái)源,表,也可以是表的結(jié)合關(guān)系
// where 條件
// group by 分組
// having 對(duì)分組設(shè)定過(guò)濾條件
// order by 對(duì)前面取得的數(shù)據(jù)來(lái)指定按某個(gè)字段的大小進(jìn)行排序. ASC(正序,默認(rèn)) DESC(倒序)
// 如果指定多個(gè)字段排序,則其含義是,在前一個(gè)字段排序中相同的那些數(shù)據(jù)里,再按后一字段的大小進(jìn)行排序.
// limit [起始行號(hào) start],[要取出的行數(shù) num] --用于分頁(yè)
// 顯示取得第n頁(yè)數(shù)據(jù): select *from t_name limit ($n-1)*$pageSize,$pageSize
2:)數(shù)據(jù)庫(kù)設(shè)計(jì)3范式
第一范式(1NF):原子性轩缤,數(shù)據(jù)不可再分
一個(gè)表中的數(shù)據(jù)(字段值)不可再分
第二范式(2NF):唯一性,消除部分依賴(lài)
一個(gè)表中的每一行必須唯一可區(qū)分贩绕,且非主鍵字段值完全依賴(lài)主鍵字段值
第三范式(3NF):獨(dú)立性火的,消除傳遞依賴(lài)
使一個(gè)表中的任何一個(gè)非主鍵,完全獨(dú)立地依賴(lài)于主鍵淑倾,而不能又依賴(lài)于另外的非主鍵
3:)連接查詢(xún)
基本形式:
from 表1 [連接方式] join 表2 [on 連接條件]馏鹤;連接的結(jié)果可以當(dāng)作一個(gè)“表”來(lái)使用。
交叉連接:
from 表1 [cross] join 表2 娇哆;連接的結(jié)果其實(shí)是兩個(gè)表中的所有數(shù)據(jù)“兩兩對(duì)接”湃累。這種連接也叫做“笛卡爾積”
內(nèi)連接:
from 表1 [inner] join 表2 on 連接條件。inner關(guān)鍵字可以省略碍讨,也可以用cross代替治力。on連接條件無(wú)非是設(shè)定在連接后所得到的數(shù)據(jù)表中,設(shè)定一個(gè)條件以取得所需要的數(shù)據(jù)勃黍。通常連接都是指兩個(gè)有關(guān)聯(lián)的表宵统,則連接條件就是這兩個(gè)表的關(guān)聯(lián)字段的一個(gè)關(guān)系(通常都是相等關(guān)系)
左[外]連接:
from 表1 left [outer] join 表2 on 連接條件;將左邊的表的數(shù)據(jù)跟右邊的表的數(shù)據(jù)以給定的條件連接覆获,并將左邊的表中無(wú)法滿足條件的數(shù)據(jù)(行)也一并取得——即左邊的表的數(shù)據(jù)肯定都取出來(lái)了
右[外]連接:
from 表1 right [outer] join 表2 on 連接條件马澈;將左邊的表的數(shù)據(jù)跟右邊的表的數(shù)據(jù)以給定的條件連接,并將右邊的表中無(wú)法滿足條件的數(shù)據(jù)也一并取得——即右邊的表的數(shù)據(jù)肯定都取出來(lái)了
4:)聯(lián)合查詢(xún)
含義:將兩個(gè)“字段一致”的查詢(xún)語(yǔ)句所查詢(xún)到的結(jié)果以“縱向堆疊”的方式合并到一起弄息,成為一個(gè)新的結(jié)果集痊班。
形式:
select語(yǔ)句1 union [ALL | DISTINCT] select語(yǔ)句2:
說(shuō)明:
兩個(gè)select語(yǔ)句的查詢(xún)結(jié)果的字段需要保持一致:個(gè)數(shù)必須相同,對(duì)應(yīng)順序上的字段類(lèi)型也應(yīng)該相同
ALL | DISTINCT表示兩表的數(shù)據(jù)聯(lián)合后是否需要消除相同行(數(shù)據(jù))摹量。ALL表示不消除(全部取得)涤伐,DISTINCT表示要消除。默認(rèn)不寫(xiě)就會(huì)消除
應(yīng)該將這個(gè)聯(lián)合查詢(xún)的結(jié)果理解為最終也是一個(gè)“表格數(shù)據(jù)”缨称,且默認(rèn)使用第一個(gè)select語(yǔ)句中的字段名
如果第一個(gè)select語(yǔ)句中的列有別名废亭,則order by子句中就必須使用該別名
### TCP通信
1:)套接字使用的步驟
初始化 -> 連接 -> 發(fā)送(接收)數(shù)據(jù) -> 關(guān)閉套接字.
2:)函數(shù)socket()
int socket(int domain,int type,int protocol);
//protocol一般取0,函數(shù)返回值是成功返回套接字描述符,
//失敗返回-1,domain一般取AF_INET,
//type: SOCK_STREAM使用TCP,SOCK_DGRAM使用UDP不可靠連接.
外部依賴(lài): #include
#include
3:)函數(shù)bind()
int bind(int sockfd,const struct sockaddr *my_addr,socklen_t addrlen);
// bind將進(jìn)程與一個(gè)套接字聯(lián)系起來(lái),通常用于服務(wù)器進(jìn)程為接入客戶連接建立一個(gè)套接口;
// sockfd是socket函數(shù)調(diào)用返回的套接口值,
// my_addr是結(jié)構(gòu)sockaddr的地址
// addrlen設(shè)置了my_addr能容納的最大字節(jié)數(shù).
4:)函數(shù)listen()
int listen(int sockfd,int backlog)
// 服務(wù)端調(diào)用該函數(shù)來(lái)監(jiān)聽(tīng)指定端口的客戶端連接
// sockfd還是socket標(biāo)示符
// backlog 最大并發(fā)數(shù)
5:)函數(shù)accept()
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
// 當(dāng)有客戶端連接到服務(wù)端,它們會(huì)排入隊(duì)列,直到服務(wù)端準(zhǔn)備好處理他們?yōu)橹?
// accept會(huì)返回一個(gè)新的套接口,同時(shí)原來(lái)的套接口繼續(xù)listen.
// accept會(huì)阻塞,直到有客戶端連接.
6:)函數(shù)connect()
int connect(int sockfd,const struct sockaddr *serv_addr,socklen_t addrlen);
// 客戶端調(diào)用connect與服務(wù)端進(jìn)行連接.
// $0表示的是客戶端的socket.
7:)函數(shù)send() --發(fā)送數(shù)據(jù)
ssize_t send(int s,const void* buf,size_t len,int flags);
// s是已經(jīng)建立連接的套接口
// buf是要發(fā)送數(shù)據(jù)內(nèi)存buffer
// len指明buffer的大小
// flags取0.
// 成功,返回發(fā)送的字節(jié)數(shù),
函數(shù)recv與send類(lèi)似:
ssize_t recv(int s,void *buf,size_t len,int flags);
最后,記得要調(diào)用close(int sockfd)來(lái)關(guān)閉socket;
### epoll函數(shù)使用舉例
struct epoll_event ev,events[100];//數(shù)組用于回傳要處理的事件
int epfd = epoll_create(100);//可以放100個(gè)socket
ev.data.fd = listen_st;//設(shè)置與要處理的事件相關(guān)的文件描述符
ev.events = EPOLLIN | EPOLLERR | EPOLLHUP(掛起);//設(shè)置要處理的事件類(lèi)型
epol_ctl(epfd,EPOLL_CTL_ADD,listen_st,&ev);//注冊(cè)epoll事件
int nfds = epoll_wait(epfd,events,100,-1);//等待epoll事件的發(fā)生
### 共享庫(kù)so
// so文件在linux為共享庫(kù)
// 編譯時(shí)gcc需要加-fPIC,使gcc產(chǎn)生與位置無(wú)關(guān)的代碼[具體函數(shù)入口位置由主調(diào)進(jìn)程處理]
// 鏈接時(shí)gcc使用-shared選項(xiàng),指示生成一個(gè).so文件
// 庫(kù)文件格式為lib*.so
// 提供一個(gè)與該共享庫(kù)配套的頭文件[聲明so文件中的函數(shù)]
// .bash_profile 中添加 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
// 使得程序鏈接時(shí)會(huì)在當(dāng)前目錄下尋找so文件
// gcc -L. -ltest -o hello hello.o [-L.表示在當(dāng)前目錄尋找so文件,-ltest表示鏈接libtest.so]
// 在.h文件中增加__cplusplus的預(yù)編譯指令,就可被C++調(diào)用這個(gè)庫(kù)了
### so文件配套的頭文件舉例
#ifndef TEST_H_
#define TEST_H_
#ifdef __cpluscplus
extern "C"
{
#endif
int max(int a,int b);
int add(int a,int b);
#ifdef __cplusplus
}
#endif
#endif
### 有名管道FIFO
$ mkfifo fifo1? ? # 創(chuàng)建有名管道fifo1
// 有名管道具有持久性
// 有名管道可在任意兩個(gè)進(jìn)程間通信
### 信號(hào)
1:)信號(hào)通常用來(lái)向一個(gè)進(jìn)程通知事件
信號(hào)是不可提前預(yù)知的,所以信號(hào)是異步的.
比如硬件異常,非法內(nèi)存引用,在鍵盤(pán)上按一個(gè)鍵等都會(huì)發(fā)出信號(hào).
ctrl+c --> 發(fā)出SIGINT信號(hào)
2:)通過(guò)fork函數(shù)產(chǎn)生的進(jìn)程與父進(jìn)程處理信號(hào)一樣.
捕捉信號(hào):signal函數(shù)
3:)守護(hù)進(jìn)程的創(chuàng)建
- 父進(jìn)程中執(zhí)行fork后,執(zhí)行exit退出
- 在子進(jìn)程中調(diào)用setsid.
- 讓根目錄/ 成為子進(jìn)程的工作目錄[會(huì)調(diào)用chdir函數(shù)]
- 把子進(jìn)程的umask設(shè)為0 [ umask(0) ]
- 關(guān)閉任何不需要的文件描述符
//與守護(hù)進(jìn)程通信,則需要向守護(hù)進(jìn)程發(fā)信號(hào)
### Shell腳本
1:)shell腳本舉例
#!/bin/sh
WHOAMI='whoami'
PID= `ps -u $WHOAMI | grep signd | awd '{print $1}'`
if (test "$PID" = "") then
./signd
fi
2:)
### man命令的使用
// atoi函數(shù)需要引入什么頭文件,不用去死記, $man atoi 查看一下就知道了
// 比如gcc命令的使用 ,$man gcc
### 棋盤(pán)坐標(biāo)的計(jì)算
* 棋盤(pán)坐標(biāo)的計(jì)算首先要搞清楚棋盤(pán)坐標(biāo)原點(diǎn)在屏幕坐標(biāo)系中的坐標(biāo)是多少,
* 再一個(gè)需要弄清楚棋盤(pán)上落點(diǎn)之間的間隔是多少;最終計(jì)算出每個(gè)棋子的屏幕坐標(biāo);
* 棋子的坐標(biāo) = 棋子在棋盤(pán)的單位坐標(biāo)*棋子的直徑+棋盤(pán)坐標(biāo)系相對(duì)于屏幕坐標(biāo)系的偏移量.
* 因?yàn)樵诒斫Y(jié)構(gòu)中紅棋的id始終在前邊,所以不管紅棋在下邊還是黑棋在下邊,都是先擺紅棋,再擺黑棋.
### 判斷是否點(diǎn)擊了某個(gè)象棋
void Scene::ccTouchEnded(CCTouch *pTouch,CCEvent *e)
{
CCPoint ptClickUp = pTouch->getLocation();//獲取手指離開(kāi)屏幕的瞬時(shí)坐標(biāo)
if(_red->boundingBox().containsPoint(ptClickUp)){
//表示精靈被點(diǎn)擊
this->_redSprClicked = true;
}
}
### 象棋的碰撞檢測(cè)
scheduleUpdate();//啟動(dòng)定時(shí)器,會(huì)每一幀調(diào)用update方法
void udpate(float delta){
//精靈默認(rèn)的錨點(diǎn)是在它的中心
//一般情況下,是判斷兩個(gè)精靈的矩形是否有相交的部分,因?yàn)檫@里有旋轉(zhuǎn),所以不能用這個(gè).
//象棋是圓形,只需判斷兩個(gè)圓的圓心距是否小于r1+r2
float x1 = m_sp1->getPositionX();
float x2 = m_sp2->getPositionY();
if(abs(x1-x2)getContentSize().width*0.5
//兩個(gè)精靈發(fā)生碰撞
//開(kāi)始游戲,進(jìn)入主場(chǎng)景
CCDirector::sharedDirector->replaceScene(SceneGame::scene());
}
}
=====================================================================================
/* 函數(shù) */
### memset函數(shù)
原型:extern void *memset(void *buffer, char c, int count);
用法:#include
功能:把buffer所指內(nèi)存區(qū)域的前count個(gè)字節(jié)設(shè)置成字符c。
說(shuō)明:返回指向buffer的指針
### strcpy函數(shù)實(shí)現(xiàn)
char *strcpy(char *strDest, const char *strSrc)
{
assert((strDest!=NULL) && (strSrc !=NULL)); // 2分
char *address = strDest; // 2分
while( (*strDest++ = * strSrc++) != ‘\0’ ) // 2分
NULL ;
return address ; // 2分
}
### inet_addr函數(shù)
/* Convert Internet host address from numbers-and-dots notation in CP
into binary data in network byte order.? */
extern in_addr_t inet_addr (const char *__cp) __THROW;
eg: inet_addr("192.168.1.23");
### setsockopt函數(shù)
int setsockopt(int s,int level,int optname,const void* optval,socklen_t optlen);
// 設(shè)置套接口,SO_REUSEADDR指示系統(tǒng)地址可重用.
int on = 1;
setsockopt(st,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
### read函數(shù)
read(STDIN_FILENO,s,sizeof(s));//從鍵盤(pán)讀取字符串,并緩存到s中
write(STDOUT_FILENO,buf,strlen(buf));//向控制臺(tái)寫(xiě)數(shù)據(jù)
### fcntl函數(shù)
int fcntl(int fd,int cmd,.../* arg */);
//該函數(shù)可以將文件或socket描述符設(shè)置為阻塞或非阻塞狀態(tài)
//fd是要設(shè)置的文件描述符或socket
//cmd F_GETFL為得到目前狀態(tài),F_SETFL為設(shè)置狀態(tài)
//宏定義0_NOBLOCK表示非阻塞,0代表阻塞
//返回值為描述符當(dāng)前狀態(tài)
### epoll_*函數(shù)
epoll相當(dāng)于一個(gè)游泳池.
epoll_create() --用來(lái)創(chuàng)建一個(gè)epoll文件描述符;需要調(diào)用close()來(lái)關(guān)閉epoll句柄.
epoll_ctl() --用來(lái)修改需要偵聽(tīng)的文件描述符或事件;
epoll_wait() --接收發(fā)生在被偵聽(tīng)的描述符上的,用戶感興趣的IO事件;
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
// epfd是epoll_create的返回值
// op EPOLL_CTL_ADD:注冊(cè)新的fd到epfd中
// fd是socket描述符
// event 通知內(nèi)核需要監(jiān)聽(tīng)什么事件
int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);
// epfd是epoll_create的返回值
// epoll_events里面將存儲(chǔ)所有的讀寫(xiě)事件
// maxevents是當(dāng)前需要監(jiān)聽(tīng)的所有socket句柄數(shù)
// timeout -1表示一直等下去
### fork函數(shù)
#include
pid_t fork(void);//進(jìn)程克隆
fork執(zhí)行成功,向父進(jìn)程返回子進(jìn)程的pid,并向子進(jìn)程返回0,函數(shù)返回0表示的是子進(jìn)程;
fork創(chuàng)建的新進(jìn)程是和父進(jìn)程一樣的副本.(除了PID和PPID);
提示: 獲取pid的方法 --> getpid(),getppid()
### execve函數(shù)
int execve(const char* path,const char *arg,char * const envp[]);
fork創(chuàng)建了一個(gè)新的進(jìn)程,產(chǎn)生一個(gè)新的PID;
execve用被執(zhí)行的程序完全替換了調(diào)用進(jìn)程的映像;
execve啟動(dòng)一個(gè)新程序,替換原有進(jìn)程,所以被執(zhí)行的進(jìn)程pid不變;
path? --? 要執(zhí)行的文件完整路徑
arg? ? --? 傳遞給程序完整參數(shù)列表
envp? --? 指向執(zhí)行execed程序的環(huán)境指針,可以設(shè)為NULL
### getcwd函數(shù)
char* getcwd(char* buf,size_t size);
該函數(shù)把當(dāng)前工作目錄的絕對(duì)路徑名復(fù)制到buf中,size指示buf的大小.
### opendir函數(shù)
DIR *opendir(const char* pathname);//打開(kāi)pathname指向的目錄文件
struct dirent *readdir(DIR *dir);//讀出目錄文件內(nèi)容
int closedir(DIR *dir);
### getlogin函數(shù)
getlogin()函數(shù)返回程序的用戶名;
struct passwd* getpwnam(const char* name);//返回/etc/passwd文件中與該登錄名相應(yīng)的一行完整信息
### system函數(shù)
int system(const char* cmd);
//該函數(shù)傳遞給/bin/.sh/cmd中可以包含選項(xiàng)和參數(shù)
//如果沒(méi)有找到/bin/sh 函數(shù)返回127,
### wait函數(shù)
pid_t wait(int *status);//阻塞調(diào)用,直到子進(jìn)程退出,wait才返回
pid_t waitpid(pid_t pid,int *status,int options);
// wait和waitpid函數(shù)收集子進(jìn)程的退出狀態(tài)
// status保存子進(jìn)程的退出狀態(tài)
// pid為等待進(jìn)程的pid
// 父進(jìn)程沒(méi)有調(diào)用wait函數(shù),子進(jìn)程就退出了,這個(gè)時(shí)候子進(jìn)程就成了僵死進(jìn)程
### exit函數(shù)
int exit(int status);
// 導(dǎo)致進(jìn)程正常終止,并且返回給父進(jìn)程的狀態(tài)
// 無(wú)論進(jìn)程為何終止,最后都執(zhí)行相同的代碼,關(guān)閉文件,釋放內(nèi)存資源
// void abort()函數(shù)會(huì)導(dǎo)致程序異常終止
### kill函數(shù)
int kill(pid_t pid,int sig);
// kill函數(shù)殺死一個(gè)進(jìn)程,由pid指定
// sig表示信號(hào)
### pipe函數(shù)
int pipe(int filedes[2]);
// 如果成功建立了管道,則會(huì)打開(kāi)兩個(gè)文件描述符,一個(gè)用于讀數(shù)據(jù),一個(gè)用于寫(xiě)數(shù)據(jù)
// 關(guān)閉管道用close函數(shù)
### mkfifo函數(shù)
int mkfifo(const char* pathname,mode_t mode);
// 創(chuàng)建fifo,函數(shù)執(zhí)行成功返回0
// pathname代表fifo的名稱(chēng)
// mode表示讀寫(xiě)權(quán)限,比如777
// unlink(const char*) 函數(shù)刪除fifo
### shmget函數(shù)
int shmget(key_t key,size_t size,int shm_flg);
// 創(chuàng)建共享內(nèi)存區(qū)
// 參數(shù)key既可以是IPC_PRIVATE,也可以是ftok函數(shù)返回的一個(gè)關(guān)鍵字
// size指定段的大小,shm_flg表示權(quán)限0xxx
// 函數(shù)成功則返回段標(biāo)示符
// 兩個(gè)進(jìn)程要共享一塊內(nèi)存,實(shí)際上是一塊內(nèi)存分別映射到兩個(gè)進(jìn)程,由操作系統(tǒng)對(duì)這塊內(nèi)存進(jìn)行同步
// $ipcs -m #查看共享內(nèi)存
### shmat函數(shù)
void* shmat(int shmid,const void* shmaddr,int shmflg);
// 附加共享內(nèi)存區(qū)
// shmid為要附加的共享內(nèi)存區(qū)標(biāo)示符
// shmaddr一般置為0,由系統(tǒng)分配地址
// shmflg可以是SHM_RDONLY只讀
// 函數(shù)成功則返回被附加了段的地址
// 函數(shù)shmdt(const void* shmaddr)是將附加在shmaddr的段從調(diào)用進(jìn)程的地址空間分離出去
### signal函數(shù)
signal(int signo,void (*func))
// signo 信號(hào)名
// func? 回調(diào)函數(shù)的名稱(chēng)
int sigaction(int signo,const struct sigaction *act,struct sigaction *oact)
該函數(shù)是signal的升級(jí)版,會(huì)檢查或修改與指定信號(hào)相關(guān)聯(lián)的處理動(dòng)作
### raise函數(shù)
int raise(int signo);
// 發(fā)送信號(hào),raise函數(shù)一般用于進(jìn)程向自身發(fā)送信號(hào).
unsigned int alarm(unsigned int seconds);
// 設(shè)置定時(shí)器,當(dāng)時(shí)間到了則發(fā)出SIGALARM信號(hào)
### sleep函數(shù)
unsigned int sleep(unsigned int seconds);
// seconds指定睡眠時(shí)間
// 到時(shí)間后函數(shù)返回.
### openlog函數(shù)
void openlog(const char* ident,int option,int facility);//打開(kāi)日志
void syslog(int priority,const char* format,...);//寫(xiě)入日志
void closelog();//關(guān)閉日志
### pthread_create函數(shù)
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,
void* (*start_routine)(void*),void *arg)
// 線程創(chuàng)建函數(shù),[在進(jìn)程中只有一個(gè)控制線程,主線程return,整個(gè)進(jìn)程就終止]
// thread是新線程的ID,
// attr_t 線程屬性
// start_routine回調(diào)函數(shù)
// arg是線程啟動(dòng)的附加參數(shù)
// 函數(shù)成功則返回0
// gcc鏈接時(shí)要加-lpthread
注: 多個(gè)線程創(chuàng)建后線程的運(yùn)行順序具有隨機(jī)性;
### pthread_exit函數(shù)
void pthread_exit(void* arg);
// 單個(gè)線程退出函數(shù)
// 任一線程調(diào)用exit函數(shù),整個(gè)進(jìn)程就會(huì)終止
// arg會(huì)被其他線程調(diào)用,比如pthread_join捕捉
// 線程中不要用信號(hào)來(lái)處理邏輯,這樣會(huì)使得程序變得很復(fù)雜
### pthread_join函數(shù)
int pthread_join(pthread_t th,void** thr_return);
// 該函數(shù)用于掛起當(dāng)前線程,直至th指定的線程終止才返回
// 如果另一個(gè)線程返回值不為空則保存在thr_return中
### pthread_detach函數(shù)
int pthread_detach(pthread_t th);
// 使線程處于被分離狀態(tài)
// 對(duì)于被分離狀態(tài)的線程,調(diào)用pthread_join無(wú)效
// 如果不等待一個(gè)線程,同時(shí)對(duì)該線程的返回值不感興趣,可以設(shè)置為該線程為被分離狀態(tài)
// 自己不能使自己成為分離狀態(tài),只能由其他線程調(diào)用pthread_detach
### pthread_cancel函數(shù)
// pthread_cancel函數(shù)允許一個(gè)線程取消th指定的另一個(gè)線程
// 函數(shù)成功則返回0
// pthread_equal函數(shù)判斷兩個(gè)線程是否是同一個(gè)線程
### pthread_attr_init函數(shù)
int pthread_attr_init(pthread_attr_t *attr);
// pthread_attr_init函數(shù)初始化attr結(jié)構(gòu)[線程屬性]
// pthread_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);#線程創(chuàng)建時(shí)則為被分離狀態(tài)
// pthread_attr_destroy函數(shù)釋放attr內(nèi)存空間
=========================================================================