多線程和多進程的應用場景
多線程模型適用于I/O密集型場景所灸,因為I/O密集型場景因為I/O阻塞導致頻繁切換,線程只占用棧譬胎,程序計數(shù)器差牛,一組寄存器等少量資源,切換效率高堰乔,單機多核分布式偏化。
多進程模型適用于需要頻繁的計算場景,多機分布式镐侯。
網(wǎng)絡的七層協(xié)議和五層協(xié)議侦讨;各層都分別有哪些協(xié)議?
TCP/IP:?
數(shù)據(jù)鏈路層:ARP,RARP?
網(wǎng)絡層: IP,ICMP,IGMP?
傳輸層:TCP ,UDP,UGP?
應用層:Telnet,FTP,SMTP,SNMP.?
OSI:?
物理層:EIA/TIA-232, EIA/TIA-499, V.35, V.24, RJ45, Ethernet, 802.3, 802.5, FDDI, NRZI, NRZ, B8ZS
數(shù)據(jù)鏈路層:Frame Relay, HDLC, PPP, IEEE 802.3/802.2, FDDI, ATM, IEEE 802.5/802.2?
網(wǎng)絡層:IP苟翻,IPX韵卤,AppleTalk DDP?
傳輸層:TCP,UDP袜瞬,SPX?
會話層:RPC,SQL,NFS,NetBIOS,names,AppleTalk,ASP,DECnet,SCP?
表示層:TIFF,GIF,JPEG,PICT,ASCII,EBCDIC,encryption,MPEG,MIDI,HTML?
應用層:FTP,WWW,Telnet,NFS,SMTP,Gateway,SNMP
http長鏈接和短連接的區(qū)別怜俐?
短連接?
連接->傳輸數(shù)據(jù)->關(guān)閉連接
HTTP是無狀態(tài)的,瀏覽器和服務器每進行一次HTTP操作邓尤,就建立一次連接拍鲤,但任務結(jié)束就中斷連接贴谎。
也可以這樣說:短連接是指SOCKET連接后發(fā)送后接收完數(shù)據(jù)后馬上斷開連接。
長連接?
連接->傳輸數(shù)據(jù)->保持連接 -> 傳輸數(shù)據(jù)-> 季稳。擅这。。 ->關(guān)閉連接景鼠。
長連接指建立SOCKET連接后不管是否使用都保持連接仲翎,但安全性較差。
http的長連接?
HTTP也可以建立長連接的铛漓,使用Connection:keep-alive溯香,HTTP 1.1默認進行持久連接。HTTP1.1和HTTP1.0相比較而言浓恶,最大的區(qū)別就是增加了持久連接支持(貌似最新的 http1.0 可以顯示的指定 keep-alive),但還是無狀態(tài)的玫坛,或者說是不可以信任的。
什么時候用長連接包晰,短連接湿镀??
長連接多用于操作頻繁,點對點的通訊伐憾,而且連接數(shù)不能太多情況勉痴。每個TCP連接都需要三步握手,這需要時間树肃,如果每個操作都是先連接蒸矛,再操作的話那么處理速度會降低很多,所以每個操作完后都不斷開扫外,次處理時直接發(fā)送數(shù)據(jù)包就OK了莉钙,不用建立TCP連接廓脆。例如:數(shù)據(jù)庫的連接用長連接筛谚, 如果用短連接頻繁的通信會造成socket錯誤,而且頻繁的socket 創(chuàng)建也是對資源的浪費停忿。
而像WEB網(wǎng)站的http服務一般都用短鏈接驾讲,因為長連接對于服務端來說會耗費一定的資源,而像WEB網(wǎng)站這么頻繁的成千上萬甚至上億客戶端的連接用短連接會更省一些資源席赂,如果用長連接吮铭,而且同時有成千上萬的用戶,如果每個用戶都占用一個連接的話颅停,那可想而知吧谓晌。所以并發(fā)量大,但每個用戶無需頻繁操作情況下需用短連好癞揉。
總之,長連接和短連接的選擇要視情況而定践美。?
TCP協(xié)議在每次建立連接時暑认,都要在收發(fā)雙方之間交換?(? ?三個? )?報文
TCP建立連接的過程會交換哪些信息(起始的序列號、窗口姐刁、各種選項)?烦味?聂使?
string簡單實現(xiàn)
#include <iostream>
#include <string>
using namespace std;
class String
{
public:
? ? String(const char* str = NULL);//通用構(gòu)造函數(shù),String("abc")
? ? String(const String &str);//拷貝構(gòu)造
? ? ~String();
? ? String& operator=(const String &str);//賦值運算符。返回引用
? ? String operator+(const String &str) const;
? ? String& operator+=(const String &str);//+=操作符谬俄。返回引用
? ? char& operator[](int n) const;//下標操作符柏靶。返回引用
? ? bool operator==(const String &str) const;
? ? int size() const;//字符串實際大小,不包括結(jié)束符
? ? const char *c_str() const;//將string轉(zhuǎn)為char *
private:
? ? char *data;
? ? int length;
};
String::String(const char* str)//通用構(gòu)造
{
? ? if (!str)
? ? {//為空溃论。String a()
? ? ? ? length = 0;
? ? ? ? data = new char[1];
? ? ? ? *data = '\0';
? ? }
? ? else
? ? {
? ? ? ? length = strlen(str);
? ? ? ? data = new char[length + 1];
? ? ? ? strcpy(data, str);//會拷貝源的結(jié)束符
? ? }
}
String::String(const String &str)//拷貝構(gòu)造宿礁,深拷貝
{
? ? length = str.size();
? ? data = new char[length + 1];
? ? strcpy(data, str.c_str());
}
String::~String()
{
? ? delete[] data;
? ? length = 0;
}
String& String::operator=(const String &str)//賦值操作符4步
{
? ? if (this == &str) return *this;//1 自我賦值,返回自身引用
? ? delete[] data;//2 刪除原有數(shù)據(jù)
? ? length = str.size();//3 深拷貝
? ? data = new char[length + 1];
? ? strcpy(data, str.c_str());
? ? return *this;//4 返回自身引用
}
String String::operator+(const String &str) const//+操作符3步
{//新建對象包括新空間蔬芥,拷貝兩個數(shù)據(jù)梆靖,返回新空間
? ? String newString;
? ? newString.length = length + str.size();
? ? newString.data = new char[newString.length + 1];
? ? strcpy(newString.data, data);
? ? strcat(newString.data, str.data);
? ? return newString;
}
String& String::operator+=(const String &str)//+=操作符5步
{//重分配新空間,拷貝兩個數(shù)據(jù)笔诵,刪除自己原空間返吻,賦值為新空間,返回引用
? ? length += str.size();//成員length是實際長度
? ? char *newdata = new char[length + 1];
? ? strcpy(newdata, data);
? ? strcat(newdata, str.c_str());
? ? delete[] data;
? ? data = newdata;
? ? return *this;
}
char& String::operator[](int n) const
{//下標操作符乎婿,返回引用
? ? if (n >= length) return data[length - 1];//如果越界测僵,返回最后一個字符
? ? else return data[n];
}
bool String::operator==(const String &str) const
{
? ? if (length != str.size()) return false;
? ? return strcmp(data, str.c_str()) ? false : true;
}
int String::size() const
{
? ? return length;
}
const char *String::c_str() const
{
? ? return data;
}
int main()
{
? ? char a[] = "Hello", b[] = "World!";
? ? String s1(a), s2(b);
? ? cout << s1.c_str() << endl;
? ? cout << s2.c_str() << endl;
? ? s1 += s2;
? ? cout << s1.c_str() << endl;
? ? s1 = s2;
? ? cout << s1.c_str() << endl;
? ? cout << (s1 + s2).c_str() << endl;
? ? cout << s1.size() << endl;
? ? cout << s1[1] << endl;
? ? if (s1 == s2)
? ? ? ? cout << "相等" << endl;
}
拷貝構(gòu)造函數(shù)為什么是常引用
一、為何要用引用:
例如谢翎,在執(zhí)行bbb.myTestFunc(aaa);時捍靠,其實會調(diào)用拷貝構(gòu)造函數(shù)。如果我們的拷貝構(gòu)造函數(shù)的參數(shù)不是引用森逮,那么在bbb.myTestFunc(aaa);時榨婆,調(diào)用CExample ex = aaa;,又因為ex之前沒有被創(chuàng)建褒侧,所以又需要調(diào)用拷貝構(gòu)造函數(shù)良风,故而又執(zhí)行CExample ex = aaa;,就這樣永遠的遞歸調(diào)用下去了闷供。
所以烟央, 拷貝構(gòu)造函數(shù)是必須要帶引用類型的參數(shù)的, 而且這也是編譯器強制性要求的歪脏。
二疑俭、為何要要用const
如果在函數(shù)中不會改變引用類型參數(shù)的值,加不加const的效果是一樣的婿失。而且不加const钞艇,編譯器也不會報錯鬼贱。但是為了整個程序的安全,還是加上const香璃,防止對引用類型參數(shù)值的意外修改这难。
孤兒進程可以理解為一個子進程的父進程英年早逝(父進程先于子進程退出),就將這樣的一個進程稱為孤兒進程葡秒。
僵尸進程:
(1)父進程成功創(chuàng)建子進程姻乓,且子進程先于父進程退出。?
(2)子進程需要父進程回收其所占資源眯牧,釋放pcb(進程控制塊)蹋岩。但是父進程不作為,不去釋放已經(jīng)退出子進程的pcb学少。?
(3)這樣的子進程變?yōu)榻┦M程剪个。?
(4)僵尸進程是一個已經(jīng)死掉了的進程。
重載和重寫的區(qū)別:
(1)范圍區(qū)別:重寫和被重寫的函數(shù)在不同的類中版确,重載和被重載的函數(shù)在同一類中扣囊。
(2)參數(shù)區(qū)別:重寫與被重寫的函數(shù)參數(shù)列表一定相同,重載和被重載的函數(shù)參數(shù)列表一定不同绒疗。
(3)virtual的區(qū)別:重寫的基類必須要有virtual修飾侵歇,重載函數(shù)和被重載函數(shù)可以被virtual修飾,也可以沒有吓蘑。
隱藏和重寫惕虑,重載的區(qū)別:
(1)與重載范圍不同:隱藏函數(shù)和被隱藏函數(shù)在不同類中。
(2)參數(shù)的區(qū)別:隱藏函數(shù)和被隱藏函數(shù)參數(shù)列表可以相同磨镶,也可以不同溃蔫,但函數(shù)名一定同;當參數(shù)不同時琳猫,無論基類中的函數(shù)是否被virtual修飾伟叛,基類函數(shù)都是被隱藏,而不是被重寫沸移。?
循環(huán)引用
https://blog.csdn.net/sai_j/article/details/82908241
拷貝構(gòu)造函數(shù)起作用的三種情況:
1.當用類的對象去初始化同類的另一個對象時痪伦。
????Date d2(d1);
????Date d2 = d1;? //初始化語句侄榴,并非賦值語句雹锣。
2.當函數(shù)的形參是類的對象,調(diào)用函數(shù)進行形參和實參結(jié)合時癞蚕。
????void Func(A a1)? //形參是類Date的對象a1
????{? }
????int main( )
????{
????? A a
????? Func(a2); //調(diào)用Func時蕊爵,實參a2是類Date的對象,將調(diào)用拷貝構(gòu)造函數(shù)桦山,初始化形參a1.
????? return 0;
????}
3.當函數(shù)的返回值是對象攒射,函數(shù)執(zhí)行完成返回調(diào)用者時醋旦。
????A Func1()
????{
????? ? A a1(4);
????? ? return a1;? //函數(shù)的返回值是對象
????}
????int main( )
????{
????? ? A a2;
????? ? a2 = Func1();? //函數(shù)執(zhí)行完成,返回調(diào)用者時会放,調(diào)用拷貝構(gòu)造函數(shù)
????? ? return 0;
????}
????在函數(shù)Func1( )內(nèi)饲齐,執(zhí)行語句“return a1;”時,將會調(diào)用拷貝構(gòu)造函數(shù)將a1的值復制到一個匿名對象中咧最,
????這個匿名對象是編譯系統(tǒng)在主程序中臨時創(chuàng)建的捂人。函數(shù)執(zhí)行結(jié)束時對象a1消失,但臨時對象會存在于語句
????“a2 = Func( )”中矢沿。執(zhí)行完這個語句后滥搭,臨時對象的使命也就完成了,該臨時對象便自動消失了捣鲸。
異步進程通信方式---信號
同步瑟匆,是所有的操作都做完,才返回給用戶結(jié)果栽惶。即寫完數(shù)據(jù)庫之后愁溜,在相應用戶,用戶體驗不好外厂。
異步祝谚,不用等所有操作等做完,就相應用戶請求酣衷。即先相應用戶請求交惯,然后慢慢去寫數(shù)據(jù)庫,用戶體驗較好穿仪。
TCP 滑動窗口(發(fā)送窗口和接收窗口)
TCP的滑動窗口主要有兩個作用席爽,一是提供TCP的可靠性,二是提供TCP的流控特性啊片。同時滑動窗口機制還體現(xiàn)了TCP面向字節(jié)流的設(shè)計思路只锻。
發(fā)送窗口與接收窗口關(guān)系
TCP是雙工的協(xié)議,會話的雙方都可以同時接收紫谷、發(fā)送數(shù)據(jù)齐饮。TCP會話的雙方都各自維護一個“發(fā)送窗口”和一個“接收窗口”。其中各自的“接收窗口”大小取決于應用笤昨、系統(tǒng)祖驱、硬件的限制(TCP傳輸速率不能大于應用的數(shù)據(jù)處理速率)。各自的“發(fā)送窗口”則要求取決于對端通告的“接收窗口”瞒窒,要求相同捺僻。
數(shù)據(jù)庫索引為什么要用B+樹?
B/B+樹是為了磁盤或其它存儲設(shè)備而設(shè)計的一種平衡多路查找樹(相對于二叉,B樹每個內(nèi)節(jié)點有多個分支)匕坯,與紅黑樹相比束昵,在相同的的節(jié)點的情況下,一顆B/B+樹的高度遠遠小于紅黑樹的高度(在下面B/B+樹的性能分析中會提到)葛峻。B/B+樹上操作的時間通常由存取磁盤的時間和CPU計算時間這兩部分構(gòu)成锹雏,而CPU的速度非常快术奖,所以B樹的操作效率取決于訪問磁盤的次數(shù)逼侦,關(guān)鍵字總數(shù)相同的情況下B樹的高度越小,磁盤I/O所花的時間越少腰耙。
名稱 關(guān)鍵字 ????用法
增加 insert ????insert into user(name,age,sex) values(值1,值2,值3)榛丢;
刪除 delete ????delete from user where 條件;
修改 update ????update user set 字段1=值1,字段2=值2 where 條件;
查詢 select ????select * from user;
去重 distinct???? select distinct 去重字段 from user;
在···之間 between ????select * from user where age between 20 and 30; (查詢年齡在20-30之間的用戶)
模糊匹配 like ????select * from user where name like ‘張_%’; (其中_匹配 一個字符挺庞,%匹配 一個或多個)
分頁查詢 LIMIT ????SELECT * FROM user LIMIT 5; (查詢前 5 個記錄行)
記錄條數(shù) count ????select COUNT(*) from user; (查詢user表所有記錄條數(shù))
求和 sum ????select sum(age) from user;(查詢所有的年齡和)
最大最小值 max晰赞、min ????select max(age) from user;(最大的年齡最小同理)
平均值 avg ????select avg(age) from user;(所有人年齡的平均值)
排序 order by ????select * from user order by age;(默認從小到大的正序, asc 正序选侨,desc倒序)
分組 group by???? select sex,count(*) from user group by sex;(分組查詢男女總?cè)藬?shù))
分組后篩選 having 其實與where用法相似掖鱼,having后能用聚合函數(shù)where不行,分組篩選后建議用having關(guān)鍵字
在設(shè)計數(shù)據(jù)庫時需要注意哪些援制?
1.在針對表結(jié)構(gòu)設(shè)計時如果是n對n的關(guān)系戏挡,盡可能的設(shè)計成1對N的關(guān)系。避免表關(guān)聯(lián)太復雜晨仑,以便于提高查詢效率褐墅。
2.首先在定義字段名稱是盡可能以簡單字符串來完成,建議是能讀懂字段所存儲內(nèi)容的大概意思洪己,同時字段名稱的長度在14個字符以內(nèi)妥凳。
3.明確表字段是否允許為空,不建議表字段都為可為空,因為當為null時就會影響到查詢效率。
4.在設(shè)置字段類型是時需要考慮字段應該存放那些值,有效的節(jié)省空間大写鸩丁:
????????只存在兩個是否兩個值 使用 bit類型逝钥;
????????數(shù)字值 建議使用 int,大數(shù)據(jù)使用bigint,極小數(shù)據(jù)使用tinyint拱镐;
????????如果是跟錢打交道字段艘款,或者精度維度的地理位置,或者是有小數(shù)的,使用decimal;
????????時間值得使用datetime類型
????????如果是在有中文的字段 建議使用nvarchar,nchar
????????如果只是字符 使用 varchar,char
????????如果是大文本可使用text,ntext(Unicode碼)
5.每張表建聚集索引
6.針對查詢功能適當對表建立非聚集索引沃琅,但不建議建太多索引哗咆,索引太多會影響插入效率。
Linux對字符串常用操作命令
以空格分割字符串?
awk ‘{print $1}’
以特定字符分割字符串?
str=${str//,/ } ——————–//后面是分割字符串的標志符號阵难,最后一個/后面還有一個空格
剪切字符串?
cut -b|-c|-f 3 ———————–b代表字節(jié)岳枷,-c代表字符,-f代表域 后面的數(shù)組是第幾個字符
去掉字符串中的特定字符?
sed ‘s/\”//g’ s代表替換呜叫,默認字符被替換為空空繁,\后面的字符是要被替換的字符,g表示全部替換
查找近十天更改過的文件
find ./ -name * -mtime -10
1.Linux查看當前操作系統(tǒng)版本信息? cat /proc/version
2.Linux查看版本當前操作系統(tǒng)內(nèi)核信息 uname -a
3.linux查看版本當前操作系統(tǒng)發(fā)行信息 cat /etc/issue 或 cat /etc/centos-release
4.Linux查看cpu相關(guān)信息朱庆,包括型號盛泡、主頻、內(nèi)核信息等 cat /etc/cpuinfo
1.查看系統(tǒng)版本信息的命令 lsb_release -a
2.查看centos版本號 cat /etc/issue
3.使用 file /bin/ls
后臺運行進程的命令?
1娱颊、nohup
2傲诵、setsid
3、&
vector的實現(xiàn)技術(shù)箱硕,關(guān)鍵在于其對大小的控制以及重新配置時的數(shù)據(jù)移動效率拴竹,一旦vector的舊有空間滿載,如果客戶端每新增一個元素剧罩,vector擴充空間栓拜,都是配置新空間,vector動態(tài)增加大小時惠昔,并不是在原空間之后持續(xù)新空間幕与,而是以原大小的兩倍另外配置一塊較大的空間,然后將內(nèi)容拷貝過來镇防,然后才開始在原內(nèi)容之后構(gòu)造新元素啦鸣,并釋放原空間,因此来氧,一旦引起空間重新配置诫给,指向原vector的所有迭代器都失效了,這是程序員易犯的一個錯誤啦扬,務必小心蝙搔。? ?并且vector維護的是一個連續(xù)線性空間,所以支持vector隨機存取考传。
?Map是關(guān)聯(lián)容器吃型,以鍵值對的形式進行存儲,方便進行查找僚楞,關(guān)鍵詞起到索引的作用勤晚,值則表示與索引相關(guān)聯(lián)的數(shù)據(jù),以紅黑樹的結(jié)構(gòu)實現(xiàn)泉褐,插入刪除等操作都可以在O(log n)時間內(nèi)完成赐写。
?Set是關(guān)聯(lián)容器,set中每個元素都只包含一個關(guān)鍵字膜赃,set支持高效的關(guān)鍵字查詢操作---檢查每一個給定的關(guān)鍵字是否在set中挺邀,set是以紅黑樹的平衡二叉檢索樹結(jié)構(gòu)實現(xiàn)的,支持高效插入刪除端铛,插入元素的時候會自動調(diào)整二叉樹的結(jié)構(gòu)禾蚕,使得每個子樹根節(jié)點鍵值大于左子樹所有節(jié)點的鍵值您朽,小于右子樹所有節(jié)點的鍵值换淆,另外還得保證左子樹和右子樹的高度相等。
程序優(yōu)化方法:
1.消除循環(huán)的低效率
2.減少過程調(diào)用
3.消除不必要的內(nèi)存引用
4.循環(huán)展開
5.提高并行性
野指針是指存在一個指針變量倍试,但是這個指針變量指向的內(nèi)存空間已經(jīng)被釋放讯屈,這時候指針的值還是不為空涮母∽纪牵或未申請訪問受限內(nèi)存區(qū)域的指針攘已。
"野指針"的成因主要有兩種:
? ?? ???(1)指針變量沒有被初始化样勃。任何指針變量剛被創(chuàng)建時不會自動成為NULL指針,它的缺省值是隨機的剧防,它會亂指一氣峭拘。所以鸡挠,指針變量在創(chuàng)建的同時應當被初始化拣展,要么將指針設(shè)置為NULL缔逛,要么讓它指向合法的內(nèi)存。例如
? ?? ?? ?? ?? ? char *p = NULL;
? ?? ?? ?? ?? ? char *str = (char *) malloc(100);
? ?? ???(2)指針p被free或者delete之后于毙,沒有置為NULL望众,讓人誤以為p是個合法的指針。
空指針的簡單描述:
它 “與任何對象或函數(shù)的指針值都不相等”蚤氏。也就是說, 取地址操作符 & 永遠也不能得到空指針, 同樣對 malloc() 的成功調(diào)用也不會返回空指針, 如果失敗, malloc() 的確返回空指針, 這是空指針的典型用法:表示 “未分配”或者 “尚未指向任何地方”的指針踊兜。
空指針和未初始化的指針:
空指針在概念上不同于未初始化的指針∮谟危空指針可以確保不指向任何對象或函數(shù); 而未初始化指針則可能指向任何地方贰剥。
野指針是如何產(chǎn)生的
野指針的產(chǎn)生有以下3種情況
1蚌成、定義一個指針變量時沒有初始化
int *p;
2担忧、動態(tài)開辟的內(nèi)存空間在使用完后調(diào)用free函數(shù)釋放掉這段內(nèi)存空間瓶盛,
//卻沒有將對應的指針職位NULL惩猫。雖然開辟的空間被釋放掉但指針依舊存在帆锋。
int func()
{
? ? int *p = malloc(sizeof(int));
? ? free(p);//沒有將p值為NULL的操作
}
3锯厢、對指針的操作已經(jīng)超出了指針變量的作用域
比如通常我們實現(xiàn)了一個函數(shù)实辑,該函數(shù)里創(chuàng)建了一個指針變量,而函數(shù)結(jié)束時最終返回這個指針變量摄乒,但是函數(shù)調(diào)用結(jié)束后馍佑,該函數(shù)的函數(shù)棧幀就會被銷毀拭荤,所以返回的這個指針變量所指向的空間已經(jīng)被釋放了舅世,因此這個指針變量指向的空間就變成了隨機的雏亚。
使用野指針會產(chǎn)生的后果
我們知道野指針是指向一個不可知地址的指針罢低,這里分為3種情況:
1奕短、指向不可訪問的地址
危害:觸發(fā)段錯誤翎碑。
2日杈、指向一個可用的莉擒,但是沒有明確意義的空間
危害:程序可以正確運行涨冀,但通常這種情況下鹿鳖,我們就會認為我們的程序是正確的沒有問題的翅帜,然而事實上就是有問題存在,所以這樣就掩蓋了我們程序上的錯誤绣版。
3杂抽、指向一個可用的默怨,而且正在被使用的空間
危害:如果我們對這樣一個指針進行解引用,對其所指向的空間內(nèi)容進行了修改济竹,但是實際上這塊空間正在被使用送浊,那么這個時候變量的內(nèi)容突然被改變袭景,當然就會對程序的運行產(chǎn)生影響耸棒,因為我們所使用的變量已經(jīng)不是我們所想要使用的那個值了与殃。通常這樣的程序都會崩潰幅疼,或者數(shù)據(jù)被損壞爽篷。
如何避免?
1逐工、定義一個指針變量時一定記得初始化
2钻弄、動態(tài)開辟的內(nèi)存空間使用完free之后一定將對應的指針置為NULL
3窘俺、不要在函數(shù)中返回椓隼幔空間的指針和引用
4对途、注意在使用時對指針的合法性的判斷
內(nèi)存泄露就是系統(tǒng)回收不了那些分配出去但是又不使用的內(nèi)存, 隨著程序的運行,可以使用的內(nèi)存就會越來越少,機子就會越來越卡,直到內(nèi)存數(shù)據(jù)溢出,然后程序就會掛掉,再跟著操作系統(tǒng)也可能無響應. 接著你就按重啟了惶洲。
線程通信方式:
互斥恬吕、事件铐料、臨界區(qū)钠惩、消息隊列
線程安全?
一般說來篓跛,確保線程安全的方法有這幾個:競爭與原子操作举塔、同步與鎖央渣、可重入芽丹、防過度優(yōu)化拔第。
競爭與原子操作?
多個線程同時訪問和修改一個數(shù)據(jù)蚊俺,可能造成很嚴重的后果泳猬。出現(xiàn)嚴重后果的原因是很多操作被操作系統(tǒng)編譯為匯編代碼之后不止一條指令得封,因此在執(zhí)行的時候可能執(zhí)行了一半就被調(diào)度系統(tǒng)打斷了而去執(zhí)行別的代碼了拷呆。一般將單指令的操作稱為原子的(Atomic)茬斧,因為不管怎樣啥供,單條指令的執(zhí)行是不會被打斷的。
因此瞬欧,為了避免出現(xiàn)多線程操作數(shù)據(jù)的出現(xiàn)異常艘虎,Linux系統(tǒng)提供了一些常用操作的原子指令野建,確保了線程的安全候生。但是唯鸭,它們只適用于比較簡單的場合明肮,在復雜的情況下就要選用其他的方法了柿估。
同步與鎖?
為了避免多個線程同時讀寫一個數(shù)據(jù)而產(chǎn)生不可預料的后果官份,開發(fā)人員要將各個線程對同一個數(shù)據(jù)的訪問同步舅巷,也就是說钠右,在一個線程訪問數(shù)據(jù)未結(jié)束的時候,其他線程不得對同一個數(shù)據(jù)進行訪問狠毯。
同步的最常用的方法是使用鎖(Lock)嚼松,它是一種非強制機制献酗,每個線程在訪問數(shù)據(jù)或資源之前首先試圖獲取鎖罕偎,并在訪問結(jié)束之后釋放鎖颜及;在鎖已經(jīng)被占用的時候試圖獲取鎖時,線程會等待乾翔,直到鎖重新可用反浓。
二元信號量是最簡單的一種鎖雷则,它只有兩種狀態(tài):占用與非占用月劈,它適合只能被唯一一個線程獨占訪問的資源惭墓。對于允許多個線程并發(fā)訪問的資源腊凶,要使用多元信號量(簡稱信號量)钧萍。
可重入?
一個函數(shù)被重入风瘦,表示這個函數(shù)沒有執(zhí)行完成,但由于外部因素或內(nèi)部因素蟹略,又一次進入該函數(shù)執(zhí)行。一個函數(shù)稱為可重入的状婶,表明該函數(shù)被重入之后不會產(chǎn)生任何不良后果∩缘叮可重入是并發(fā)安全的強力保障账月,一個可重入的函數(shù)可以在多線程環(huán)境下放心使用局齿。
防過度優(yōu)化?
在很多情況下讥此,即使我們合理地使用了鎖萄喳,也不一定能夠保證線程安全他巨,因此,我們可能對代碼進行過度的優(yōu)化以確保線程安全觉痛。
我們可以使用volatile關(guān)鍵字試圖阻止過度優(yōu)化薪棒,它可以做兩件事:第一,阻止編譯器為了提高速度將一個變量緩存到寄存器而不寫回吧史;第二贸营,阻止編譯器調(diào)整操作volatile變量的指令順序。
手寫strcpy
char * strcpy(char *dst,const char *src) //[1]
{
? ? assert(dst != NULL && src != NULL);? ? //[2]
? ? char *ret = dst;? //[3]
? ? while ((*dst++=*src++)!='\0'); //[4]
? ? return ret;
}
注意問題:
[1]const修飾
源字符串參數(shù)用const修飾冰啃,防止修改源字符串阎毅。
[2]空指針檢查
(A)不檢查指針的有效性净薛,說明答題者不注重代碼的健壯性肃拜。
(B)檢查指針的有效性時使用assert(!dst && !src);
char *轉(zhuǎn)換為bool即是類型隱式轉(zhuǎn)換士聪,這種功能雖然靈活剥悟,但更多的是導致出錯概率增大和維護成本升高区岗。
(C)檢查指針的有效性時使用assert(dst != 0 && src != 0);
直接使用常量(如本例中的0)會減少程序的可維護性。而使用NULL代替0藐鹤,如果出現(xiàn)拼寫錯誤,編譯器就會檢查出來肄满。
[3]返回目標地址
(A)忘記保存原始的strdst值。
[4]'\0'
(A)循環(huán)寫成while (*dst++=*src++);明顯是錯誤的。
(B)循環(huán)寫成while (*src!='\0') *dst++=*src++;
循環(huán)體結(jié)束后恩敌,dst字符串的末尾沒有正確地加上'\0'瞬测。
C語言文件操作API
FILE這個結(jié)構(gòu)包含了文件操作的基本屬性,對文件的操作都要通過這個結(jié)構(gòu)的指針來進行,此種文件操作常用的函數(shù)見下表 函數(shù) 功能
fopen() 打開流
fclose() 關(guān)閉流
fputc() 寫一個字符到流中
fgetc() 從流中讀一個字符
fseek() 在流中定位到指定的字符
fputs() 寫字符串到流
fgets() 從流中讀一行或指定個字符
fprintf() 按格式輸出到流
fscanf() 從流中按格式讀取
feof() 到達文件尾時返回真值
ferror() 發(fā)生錯誤時返回其值
rewind() 復位文件定位器到文件開始處
remove() 刪除文件
fread() 從流中讀指定個數(shù)的字符
fwrite() 向流中寫指定個數(shù)的字符
tmpfile() 生成一個臨時文件流
tmpnam() 生成一個唯一的文件名
二月趟、直接I/O文件操作
函數(shù) 說明
open() 打開一個文件并返回它的句柄
close() 關(guān)閉一個句柄
lseek() 定位到文件的指定位置
read() 塊讀文件
write() 塊寫文件
eof() 測試文件是否結(jié)束
filelength() 取得文件長度
rename() 重命名文件
chsize() 改變文件長度
https://blog.csdn.net/tantion/article/details/85927721
兩個結(jié)點的最近公共祖先
/**
* Definition for a binary tree node.
* struct TreeNode {
*? ? int val;
*? ? TreeNode *left;
*? ? TreeNode *right;
*? ? TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
? ? TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
? ? ? ? if(p == NULL || q == NULL || root == NULL)
? ? ? ? ? ? return NULL;
? ? ? ? if(p->val < root->val && q->val < root->val)
? ? ? ? ? ? return lowestCommonAncestor(root->left, p, q);
? ? ? ? if(p->val > root->val && q->val > root->val)
? ? ? ? ? ? return lowestCommonAncestor(root->right, p, q);
? ? ? ? return root;
? ? }
};
二叉樹距離最遠的兩個節(jié)點灯蝴?
//后序 求 每個節(jié)點最遠距離孝宗, 倒著遍歷穷躁, 只遍歷了一遍 O( N )
//如果從上往下遍歷 則 O( N*N )
int GetMaxPathLen( Node* root, int& maxLen ) //maxLen初始值傳0
{
//別用 全局變量(存在線程安全問題)
if ( NULL == root )
return 0;
int left = GetMaxPathLen( root->_left, maxLen );
int right = GetMaxPathLen( root->_right, maxLen );
if ( left + right > maxLen )
maxLen = left + right;
//返回高度
return (left>right? left:right) + 1;
}
//運行結(jié)束后的 maxLen值 就是樹中最遠的兩個節(jié)點的距離
紅黑樹和B樹應用場景有何不同?
2者都是有序數(shù)據(jù)結(jié)構(gòu)因妇,可用作數(shù)據(jù)容器问潭。紅黑樹多用在內(nèi)部排序,即全放在內(nèi)存中的婚被,微軟STL的map和set的內(nèi)部實現(xiàn)就是紅黑樹狡忙。B樹多用在內(nèi)存里放不下,大部分數(shù)據(jù)存儲在外存上時址芯。因為B樹層數(shù)少灾茁,因此可以確保每次操作,讀取磁盤的次數(shù)盡可能的少谷炸。
在數(shù)據(jù)較小北专,可以完全放到內(nèi)存中時,紅黑樹的時間復雜度比B樹低旬陡。反之拓颓,數(shù)據(jù)量較大,外存中占主要部分時季惩,B樹因其讀磁盤次數(shù)少降淮,而具有更快的速度涕蜂。
B樹相對于紅黑樹的區(qū)別
在大規(guī)模數(shù)據(jù)存儲的時候,紅黑樹往往出現(xiàn)由于樹的深度過大而造成磁盤IO讀寫過于頻繁,進而導致效率低下的情況看政。為什么會出現(xiàn)這樣的情況,我們知道要獲取磁盤上數(shù)據(jù)碘箍,必須先通過磁盤移動臂移動到數(shù)據(jù)所在的柱面匾鸥,然后找到指定盤面,接著旋轉(zhuǎn)盤面找到數(shù)據(jù)所在的磁道蜜另,最后對數(shù)據(jù)進行讀寫适室。磁盤IO代價主要花費在查找所需的柱面上,樹的深度過大會造成磁盤IO頻繁讀寫举瑰。根據(jù)磁盤查找存取的次數(shù)往往由樹的高度所決定捣辆,所以,只要我們通過某種較好的樹結(jié)構(gòu)減少樹的結(jié)構(gòu)盡量減少樹的高度此迅,B樹可以有多個子女汽畴,從幾十到上千旧巾,可以降低樹的高度。
B樹和B+樹的區(qū)別
B樹:所有葉子結(jié)點都出現(xiàn)在同一層忍些,葉子結(jié)點不包含任何關(guān)鍵字信息鲁猩。
B+樹:所有的葉子結(jié)點中包含了全部關(guān)鍵字的信息,及指向含有這些關(guān)鍵字記錄的指針罢坝,且葉子結(jié)點本身依關(guān)鍵字的大小自小而大的順序鏈接廓握,所有的非終端結(jié)點可以看成是索引部分,結(jié)點中僅含有其子樹根結(jié)點中最大(或最朽夷稹)關(guān)鍵字隙券。?(而B 樹的非終節(jié)點也包含需要查找的有效信息)
為什么說B+比B樹更適合實際應用中操作系統(tǒng)的文件索引和數(shù)據(jù)庫索引?
1)?B+的磁盤讀寫代價更低
B+的內(nèi)部結(jié)點并沒有指向關(guān)鍵字具體信息的指針痹仙。因此其內(nèi)部結(jié)點相對B樹更小是尔。如果把所有同一內(nèi)部結(jié)點的關(guān)鍵字存放在同一盤塊中,那么盤塊所能容納的關(guān)鍵字數(shù)量也越多开仰。一次性讀入內(nèi)存中的需要查找的關(guān)鍵字也就越多拟枚。相對來說IO讀寫次數(shù)也就降低了。
2)?B±tree的查詢效率更加穩(wěn)定
由于非終結(jié)點并不是最終指向文件內(nèi)容的結(jié)點众弓,而只是葉子結(jié)點中關(guān)鍵字的索引恩溅。所以任何關(guān)鍵字的查找必須走一條從根結(jié)點到葉子結(jié)點的路。所有關(guān)鍵字查詢的路徑長度相同谓娃,導致每一個數(shù)據(jù)的查詢效率相當脚乡。
數(shù)據(jù)庫索引采用B+樹的主要原因是 B樹在提高了磁盤IO性能的同時并沒有解決元素遍歷的效率低下的問題。正是為了解決這個問題滨达,B+樹應運而生奶稠。B+樹只要遍歷葉子節(jié)點就可以實現(xiàn)整棵樹的遍歷。而且在數(shù)據(jù)庫中基于范圍的查詢是非常頻繁的捡遍,而B樹不支持這樣的操作(或者說效率太低)
.內(nèi)核態(tài)與用戶態(tài)的區(qū)別
內(nèi)核態(tài)與用戶態(tài)是操作系統(tǒng)的兩種運行級別锌订,當程序運行在3級特權(quán)級上時,就可以稱之為運行在用戶態(tài)画株。因為這是最低特權(quán)級辆飘,是普通的用戶進程運行的特權(quán)級,大部分用戶直接面對的程序都是運行在用戶態(tài)谓传;
當程序運行在0級特權(quán)級上時蜈项,就可以稱之為運行在內(nèi)核態(tài)。
運行在用戶態(tài)下的程序不能直接訪問操作系統(tǒng)內(nèi)核數(shù)據(jù)結(jié)構(gòu)和程序续挟。當我們在系統(tǒng)中執(zhí)行一個程序時紧卒,大部分時間是運行在用戶態(tài)下的,在其需要操作系統(tǒng)幫助完成某些它沒有權(quán)力和能力完成的工作時就會切換到內(nèi)核態(tài)(比如操作硬件)诗祸。
這兩種狀態(tài)的主要差別是
處于用戶態(tài)執(zhí)行時常侦,進程所能訪問的內(nèi)存空間和對象受到限制浇冰,其所處于占有的處理器是可被搶占的
處于內(nèi)核態(tài)執(zhí)行時,則能訪問所有的內(nèi)存空間和對象聋亡,且所占有的處理器是不允許被搶占的。
Linux系統(tǒng)是依靠軟中斷來實現(xiàn)用戶態(tài)到內(nèi)核態(tài)的切換的际乘。具體過程可分為以下幾步:
1坡倔、用戶程序執(zhí)行到調(diào)用系統(tǒng)調(diào)用處引發(fā)一個異常,這個異常就是觸發(fā)int&0x80指令
2脖含、int&0x80會導致系統(tǒng)切換到內(nèi)核態(tài)罪塔,并執(zhí)行第128號異常(中斷)處理程序
3、而第128號異常處理程序就是用來執(zhí)行系統(tǒng)調(diào)用的养葵。
字符串反轉(zhuǎn)單詞
string reverseWords(string s) {
? ? ? ? int front = 0;
? ? ? ? for(int i = 0; i <= s.length(); ++i){
? ? ? ? ? ? if(i == s.length() || s[i] == ' '){
? ? ? ? ? ? ? ? reverse(&s[front], &s[i]);
? ? ? ? ? ? ? ? front = i + 1;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return s;
? ? }
class Solution {
public:
? ? int maxProfit(vector<int>& prices) {
? ? ? ? int buyprice = INT_MAX;
? ? ? ? int benifit = 0;
? ? ? ? for (int i = 0; i < prices.size();i++){
? ? ? ? ? ? if (prices[i] < buyprice ){
? ? ? ? ? ? ? ? buyprice = prices[i];
? ? ? ? ? ? }
? ? ? ? ? ? else if (prices[i]-buyprice > benifit){
? ? ? ? ? ? ? ? benifit = prices[i]-buyprice;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return benifit;
? ? }
};
海量字符流判重問題(bitmap征堪,布隆過濾器)
功能:把格式化的數(shù)據(jù)寫入某個字符串緩沖區(qū)。
頭文件:stdio.h
原型:int sprintf( char *buffer, const char *format, [ argument] … );
參數(shù)列表:buffer:char型指針关拒,指向?qū)⒁獙懭氲淖址木彌_區(qū)佃蚜;format:格式化字符串;[argument]...:可選參數(shù)着绊,可以是任何類型的數(shù)據(jù)谐算。
返回值: 返回成功寫入buffer 的字符數(shù),出錯則返回-1. 如果 buffer 或 format 是空指針归露,且不出錯而繼續(xù)洲脂,函數(shù)將返回-1,并且 errno 會被設(shè)置為 EINVAL剧包。sprintf 返回被寫入buffer 的字節(jié)數(shù)恐锦,結(jié)束字符‘\0’不計入內(nèi)。即疆液,如果“Hello”被寫入空間足夠大的buffer后一铅,函數(shù)sprintf 返回5。
功能:用于將格式化的數(shù)據(jù)寫入字符串
*1 如果格式化后的字符串長度 < n枚粘,則將此字符串全部復制到str中馅闽,并給其后添加一個字符串結(jié)束符('\0');
*2 如果格式化后的字符串長度 >= n馍迄,則只將其中的(n-1)個字符復制到str中福也,并給其后添加一個字符串結(jié)束符('\0'),返回值為欲寫入的字符串長度攀圈。(跟編譯器有關(guān))
頭文件:stdio.h
原型:int snprintf(char *str, int n, char * format [, argument, ...]);
參數(shù)列表:str為要寫入的字符串暴凑;n為要寫入的字符的最大數(shù)目,超過n會被截斷赘来;format為格式化字符串现喳,與printf()函數(shù)相同凯傲;[argument]...:可選參數(shù),可以是任何類型的數(shù)據(jù)嗦篱。
返回值:成功則返回參數(shù)str 字符串長度冰单,失敗則返回-1,錯誤原因存于errno 中灸促。
**注意**:snprintf()并不是標C中規(guī)定的函數(shù)诫欠,在GCC中,該函數(shù)名稱就snprintf()浴栽,而在VC中稱為_snprintf()荒叼。由于不是標準函數(shù),沒有一個統(tǒng)一的標準來規(guī)定該函數(shù)的行為典鸡。所以不同編譯器結(jié)果可能不同被廓。[參考](http://c.biancheng.net/cpp/html/2417.html)
在VS2008中需在預編譯處加入
區(qū)別
snprintf比sprintf更加安全,可以控制寫入字符串長度萝玷;
snprintf會先把目標字符串清空嫁乘,然后寫入;而sprintf不會间护。這會導致問題參考
返回值不同亦渗。snprintf成功則返回欲寫入字符串長度即格式化后字符串長度,失敗則返回負值汁尺;sprintf返回成功寫入字符串長度法精,出錯返回-1。所以在使用返回值時候一定要注意特別是snprintf痴突;
一搂蜓、為什么會出現(xiàn)內(nèi)存溢出問題?導致內(nèi)存溢出問題的原因有很多辽装,比如:
(1) 使用非類型安全(non-type-safe)的語言如 C/C++ 等帮碰。
(2) 以不可靠的方式存取或者復制內(nèi)存緩沖區(qū)。
(3) 編譯器設(shè)置的內(nèi)存緩沖區(qū)太靠近關(guān)鍵數(shù)據(jù)結(jié)構(gòu)拾积。
下面來分析這些因素:
1. 內(nèi)存溢出問題是 C 語言或者 C++ 語言所固有的缺陷殉挽,它們既不檢查數(shù)組邊界,又不檢查類型可靠性(type-safety)拓巧。眾所周知斯碌,用 C/C++ 語言開發(fā)的程序由于目標代碼非常接近機器內(nèi)核,因而能夠直接訪問內(nèi)存和寄存器肛度,這種特性大大提升了 C/C++ 語言代碼的性能傻唾。只要合理編碼,C/C++ 應用程序在執(zhí)行效率上必然優(yōu)于其它高級語言承耿。然而冠骄,C/C++ 語言導致內(nèi)存溢出問題的可能性也要大許多伪煤。其他語言也存在內(nèi)容溢出問題,但它往往不是程序員的失誤凛辣,而是應用程序的運行時環(huán)境出錯所致抱既。
2. 當應用程序讀取用戶(也可能是惡意攻擊者)數(shù)據(jù),試圖復制到應用程序開辟的內(nèi)存緩沖區(qū)中蟀给,卻無法保證緩沖區(qū)的空間足夠時(換言之蝙砌,假設(shè)代碼申請了 N 字節(jié)大小的內(nèi)存緩沖區(qū),隨后又向其中復制超過 N 字節(jié)的數(shù)據(jù))跋理。內(nèi)存緩沖區(qū)就可能會溢出。想一想恬总,如果你向 12 盎司的玻璃杯中倒入 16 盎司水前普,那么多出來的 4 盎司水怎么辦?當然會滿到玻璃杯外面了壹堰!
3. 最重要的是拭卿,C/C++ 編譯器開辟的內(nèi)存緩沖區(qū)常常鄰近重要的數(shù)據(jù)結(jié)構(gòu)。現(xiàn)在假設(shè)某個函數(shù)的堆棧緊接在在內(nèi)存緩沖區(qū)后面時贱纠,其中保存的函數(shù)返回地址就會與內(nèi)存緩沖區(qū)相鄰峻厚。此時,惡意攻擊者就可以向內(nèi)存緩沖區(qū)復制大量數(shù)據(jù)谆焊,從而使得內(nèi)存緩沖區(qū)溢出并覆蓋原先保存于堆棧中的函數(shù)返回地址惠桃。這樣,函數(shù)的返回地址就被攻擊者換成了他指定的數(shù)值辖试;一旦函數(shù)調(diào)用完畢辜王,就會繼續(xù)執(zhí)行“函數(shù)返回地址”處的代碼。非但如此罐孝,C++ 的某些其它數(shù)據(jù)結(jié)構(gòu)呐馆,比如 v-table 、例外事件處理程序莲兢、函數(shù)指針等汹来,也可能受到類似的攻擊。
二改艇、解決內(nèi)存溢出問題不要太悲觀收班,下面討論內(nèi)存溢出問題的解決和預防措施。
1遣耍、改用受控代碼
2闺阱、遵守黃金規(guī)則
當你用 C/C++ 書寫代碼時,應該處處留意如何處理來自用戶的數(shù)據(jù)舵变。如果一個函數(shù)的數(shù)據(jù)來源不可靠酣溃,又用到內(nèi)存緩沖區(qū)瘦穆,那么它就必須嚴格遵守下列規(guī)則:
必須知道內(nèi)存緩沖區(qū)的總長度。
檢驗內(nèi)存緩沖區(qū)赊豌。
提高警惕扛或。
多態(tài)性,在c++中指具有不同功能的函數(shù)可以用同一個函數(shù)名碘饼,即可以用同一個函數(shù)名調(diào)用不同內(nèi)容的函數(shù)熙兔。向不同的對象發(fā)送用一個消息,不同的對象在接收同樣的消息艾恼,會產(chǎn)生不同的行為(方法)住涉。
從系統(tǒng)實現(xiàn)角度來看。多態(tài)性分為兩類:靜態(tài)多態(tài)性和動態(tài)多態(tài)性钠绍。
靜態(tài)多態(tài)性:在程序編譯時系統(tǒng)就能決定調(diào)用哪個函數(shù)舆声,因此靜態(tài)函數(shù)有稱編譯時的多態(tài)性(實質(zhì)上是通過函數(shù)的重載實現(xiàn))。例如:函數(shù)的重載和運算符重載實現(xiàn).
動態(tài)多態(tài)性:運行過程中才動態(tài)地確定操作指針所指的對象柳爽。主要通過虛函數(shù)和重寫來實現(xiàn)媳握。
虛函數(shù)vptr的初始化時間
vptr都是在自身構(gòu)造函數(shù)體之前初始化,vptr初始化是在初始化列表之前還是之后是跟編譯器實現(xiàn)有關(guān)的
TCP慢啟動
TCP在連接過程的三次握手完成后磷脯,開始傳數(shù)據(jù)蛾找,并不是一開始向網(wǎng)絡通道中發(fā)送大量的數(shù)據(jù)包,這樣很容易導致網(wǎng)絡中路由器緩存空間耗盡赵誓,從而發(fā)生擁塞打毛;而是根據(jù)初始的cwnd大小逐步增加發(fā)送的數(shù)據(jù)量,cwnd初始化為1個最大報文段(MSS)大屑懿堋(這個值可配置不一定是1個MSS)隘冲;每當有一個報文段被確認,cwnd大小指數(shù)增長绑雄。
TCP_NODELAY選項是用來控制是否開啟Nagle算法展辞,該算法是為了提高較慢的廣域網(wǎng)傳輸效率,減小小分組的報文個數(shù)万牺,完整描述:
該算法要求一個TCP連接上最多只能有一個未被確認的小分組罗珍,在該小分組的確認到來之前,不能發(fā)送其他小分組脚粟。
套接字上設(shè)置了TCP_NODELAY覆旱。有的包頭的包將被立即傳輸,在某些情況下(取決于內(nèi)部的包計數(shù)器)核无,因為這個包成功的被對方收到后需要請求對方確認扣唱。這樣,大量數(shù)據(jù)的傳輸就會被推遲而且產(chǎn)生了不必要的網(wǎng)絡流量交換。
map:
優(yōu)點:
有序性噪沙,這是map結(jié)構(gòu)最大的優(yōu)點炼彪,其元素的有序性在很多應用中都會簡化很多的操作
紅黑樹,內(nèi)部實現(xiàn)一個紅黑書使得map的很多操作在lgn的時間復雜度下就可以實現(xiàn)正歼,因此效率非常的高
缺點: 空間占用率高辐马,因為map內(nèi)部實現(xiàn)了紅黑樹,雖然提高了運行效率局义,但是因為每一個節(jié)點都需要額外保存父節(jié)點喜爷、孩子節(jié)點和紅/黑性質(zhì),使得每一個節(jié)點都占用大量的空間
適用處:對于那些有順序要求的問題萄唇,用map會更高效一些
unordered_map:
優(yōu)點: 因為內(nèi)部實現(xiàn)了哈希表檩帐,因此其查找速度非常的快
缺點: 哈希表的建立比較耗費時間
適用處:對于查找問題,unordered_map會更加高效一些另萤,因此遇到查找問題轿塔,常會考慮一下用unordered_map。
1)滑動窗口的作用:
?滑動窗口機制是TCP用來控制發(fā)送數(shù)據(jù)包速率的仲墨。
?發(fā)送方每次只能發(fā)送滑動窗口內(nèi)部的數(shù)據(jù)包。
2)滑動窗口的運行方式:
?每收到一個新的確認(ack)揍障,滑動窗口的位置就向右移動一格目养。
?滑動窗口大小,受擁塞窗口(cwnd)和通告窗口(awnd)的制約毒嫡。swnd = min [ cwnd , awnd ]癌蚁。
?擁塞窗口是為了不造成阻塞,網(wǎng)絡對發(fā)送方發(fā)包數(shù)量的限制兜畸。
?通告窗口是接收方TCP緩存當前的大小努释。它阻止由于發(fā)包數(shù)量過多,超出接收方緩存的容量咬摇。
3)滑動窗口的意義:
?因特網(wǎng)中有數(shù)以萬計的TCP連接伐蒂,它們需要共享帶寬,緩存等網(wǎng)絡資源肛鹏。 TCP希望能最大效率的利用網(wǎng)絡資源逸邦,并將資源公平的分配到每條TCP連接上,還要盡量保證不讓網(wǎng)絡超負荷在扰÷萍酰滑動窗口機制有效的解決了這些問題。
DNS域名解析使用的是TCP協(xié)議還是UDP協(xié)議芒珠?
DNS在進行區(qū)域傳輸?shù)臅r候使用TCP協(xié)議桥狡,其它時候則使用UDP協(xié)議;
DNS的規(guī)范規(guī)定了2種類型的DNS服務器,一個叫主DNS服務器裹芝,一個叫輔助DNS服務器部逮。在一個區(qū)中主DNS服務器從自己本機的數(shù)據(jù)文件中讀取該區(qū)的DNS數(shù)據(jù)信息,而輔助DNS服務器則從區(qū)的主DNS服務器中讀取該區(qū)的DNS數(shù)據(jù)信息局雄。當一個輔助DNS服務器啟動時甥啄,它需要與主DNS服務器通信,并加載數(shù)據(jù)信息炬搭,這就叫做區(qū)傳送(zone transfer)蜈漓。
為什么既使用TCP又使用UDP?
首先了解一下TCP與UDP傳送字節(jié)的長度限制:
UDP報文的最大長度為512字節(jié)宫盔,而TCP則允許報文長度超過512字節(jié)融虽。當DNS查詢超過512字節(jié)時,協(xié)議的TC標志出現(xiàn)刪除標志灼芭,這時則使用TCP發(fā)送有额。通常傳統(tǒng)的UDP報文一般不會大于512字節(jié)。
區(qū)域傳送時使用TCP彼绷,主要有一下兩點考慮:
1.輔域名服務器會定時(一般時3小時)向主域名服務器進行查詢以便了解數(shù)據(jù)是否有變動巍佑。如有變動,則會執(zhí)行一次區(qū)域傳送寄悯,進行數(shù)據(jù)同步萤衰。區(qū)域傳送將使用TCP而不是UDP,因為數(shù)據(jù)同步傳送的數(shù)據(jù)量比一個請求和應答的數(shù)據(jù)量要多得多猜旬。
2.TCP是一種可靠的連接脆栋,保證了數(shù)據(jù)的準確性。
域名解析時使用UDP協(xié)議:
客戶端向DNS服務器查詢域名洒擦,一般返回的內(nèi)容都不超過512字節(jié)椿争,用UDP傳輸即可。不用經(jīng)過TCP三次握手熟嫩,這樣DNS服務器負載更低秦踪,響應更快。雖然從理論上說邦危,客戶端也可以指定向DNS服務器查詢的時候使用TCP洋侨,但事實上,很多DNS服務器進行配置的時候倦蚪,僅支持UDP查詢包希坚。
LRU是Least Recently Used的縮寫,即最近最少使用陵且,是一種常用的頁面置換算法裁僧,選擇最近最久未使用的頁面予以淘汰个束。