首先前面提到了一個(gè)思路:給隊(duì)列模型添加初步的線程保護(hù),在使用它的時(shí)候,可以不考慮會(huì)保護(hù)其免受資源爭(zhēng)奪的問(wèn)題
CRITICAL_SECTION放在 Queue.c 的實(shí)現(xiàn)當(dāng)中。PushBack PopFront 能夠自己實(shí)現(xiàn)保護(hù)自己empty 實(shí)現(xiàn)了單獨(dú)保護(hù),現(xiàn)在反過(guò)來(lái),將其保護(hù)范圍擴(kuò)大一些就行了。具體方法 Queue.c
empty_sec 這個(gè)關(guān)鍵段/臨界區(qū)static CRITICAL_SECTION io_section;newQueue 和 del_queue 里的初始化和銷(xiāo)毀關(guān)鍵段代碼。以及重點(diǎn)的 push_back 和 pop_front的代碼修改,前者變化多一些
static int push_back(queue * __restrict object, const char * __restrict src, const char * __restrict dst)
{
char* loc_src = NULL; /* 本地變量,盡量利用寄存器以及緩存 */
char* loc_dst = NULL;
combine* loc_com = NULL;
queue* loc_que = object;
size_t len_src = strlen(src); /* 獲取路徑長(zhǎng)度 */
size_t len_dst = strlen(dst);
size_t rear = 0; /* 隊(duì)列的隊(duì)尾 */
size_t front = 0; /* 隊(duì)列的隊(duì)首 */
loc_src = Malloc_s(len_src + 1); /* 分配空間 */
loc_dst = Malloc_s(len_dst + 1);
loc_com = Malloc_s(sizeof(combine));
if (loc_src == NULL || loc_dst == NULL || loc_com == NULL)
{
Free_s(loc_src); /* 特殊處理過(guò)的釋放函數(shù) */
Free_s(loc_dst);
Free_s(loc_src);
return 1;
}
strcpy(loc_src, src); /* 構(gòu)造路徑模型 */
strcpy(loc_dst, dst);
loc_com->dst_to_path = loc_dst;
loc_com->src_from_path = loc_src;
/* 進(jìn)入保護(hù) */
EnterCriticalSection(&io_section);
rear = loc_que->rear; /*獲取隊(duì)尾*/
front = loc_que->front; /*獲取隊(duì)首*/
loc_que->path_contain[rear++] = loc_com; /* 將本地路徑加入實(shí)體 */
loc_que->rear = (rear % CAPCITY); /* 用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列的步驟 */
/* 取消原先的保護(hù) */
if (loc_que->rear == loc_que->front)
{
loc_que->empty = 0;
}
LeaveCriticalSection(&io_section);
return 0;
}
注釋里寫(xiě)了很多信息,主要教之前的版本改變了一下串行代碼的順序,功能并沒(méi)有太大變化,變化的兩處地方,一個(gè)是內(nèi)存分配錯(cuò)誤判斷由三個(gè)if變成一個(gè)if,另一個(gè)是為了使臨界區(qū)內(nèi)的代碼盡可能少,所以將一些操作移動(dòng)了。
`pop_front`代碼基本沒(méi)改變只是將臨界區(qū)擴(kuò)大了保護(hù)范圍。
static combine * pop_front(queue* object)
{
EnterCriticalSection(&io_section);
size_t loc_front = object->front; /*獲取當(dāng)前隊(duì)首*/
...
// EnterCriticalSection(&empty_sec); /* 原先的臨界區(qū)起始 */
if (object->front == object->rear)
object->empty = 1;
else
object->empty = 0;
// LeaveCriticalSection(&empty_sec);
LeaveCriticalSection(&io_section);
return loc_com;
}
PopFront 和 PushBack 附近的保護(hù)操作。CRITICAL_SECTION 相對(duì)于 Mutex 不太安全,這里簡(jiǎn)單說(shuō)一下,具體請(qǐng)查詢相關(guān)資料
CRITICAL_SECTION只保證在同一個(gè)"時(shí)間"內(nèi),只有一個(gè)線程能夠運(yùn)行這段代碼,假設(shè)我在其他代碼還有對(duì)這段代碼中的資源進(jìn)行訪問(wèn),那關(guān)鍵段就不能保證什么了。Mutex的保護(hù),而不是使用CRITICAL_SECTION Mutex嗎?其實(shí)有一個(gè)更好的選擇,那就是在 Windows Vista之后引入的一個(gè)讀寫(xiě)鎖SRWLOCK,允許多個(gè)線程讀取數(shù)據(jù)或者單個(gè)線程寫(xiě)入數(shù)據(jù)
empty的關(guān)鍵段保護(hù)修改或添加上SRWLOCK讀寫(xiě)鎖的保護(hù)AcquireSRWLock(Exclusive/Shared)),離開(kāi)保護(hù)區(qū)釋放(ReleaseSRWLock(Exclusive/Shared))。TryAcquire... 操作,但是確在Windows 7以后才引入,故不在此實(shí)現(xiàn)。寫(xiě)鎖餓死,是個(gè)挺廣泛的概念,只要有讀寫(xiě)鎖的身影就必定有它,可以查閱相關(guān)資料
這一切都是需要測(cè)試,測(cè)試,再測(cè)試,之所以選擇在 Windows 平臺(tái)上開(kāi)發(fā),原因之一就是Visual Studio有一套強(qiáng)大到爆表的性能分析工具,你可以輕易找出代碼性能問(wèn)題。善用它來(lái)研究不同鎖之間的差別,性能。
很美好。。。是我自己說(shuō)的