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