在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ C/ 總結(jié)
0x0E-單線程備份(下)
0x11-套接字編程-1
0x05-C語(yǔ)言指針:(Volume-1)
0x13-套接字編程-HTTP服務(wù)器(1)
0x0C-開(kāi)始行動(dòng)
C 語(yǔ)言進(jìn)階
第一部分
0x05-C語(yǔ)言指針(Volume-2)
0x08-C語(yǔ)言效率(下)
0x07-C語(yǔ)言效率(上)
0x04 C代碼規(guī)范
0x0F-多線程備份
0x05-C語(yǔ)言變量
第四部分
0x16-套接字編程-HTTP服務(wù)器(4)
0x0D-單線程備份(上)
總結(jié)
0x01-C語(yǔ)言序言
0x15-套接字編程-HTTP服務(wù)器(3)
0x14-套接字編程-HTTP服務(wù)器(2)
0x17-套接字編程-HTTP服務(wù)器(5)
第三部分
我的C語(yǔ)言
0x06-C語(yǔ)言預(yù)處理器
0x09-未曾領(lǐng)略的新風(fēng)景
0x0A-C線程和Glib的視角
第二部分
0x10-網(wǎng)絡(luò)的世界
0x12-套接字編程-2
0x03-C代碼
0x0B-C語(yǔ)言錯(cuò)誤處理

總結(jié)

總結(jié)

  • 首先前面提到了一個(gè)思路:給隊(duì)列模型添加初步的線程保護(hù),在使用它的時(shí)候,可以不考慮會(huì)保護(hù)其免受資源爭(zhēng)奪的問(wèn)題

    • 實(shí)際上就是將CRITICAL_SECTION放在 Queue.c 的實(shí)現(xiàn)當(dāng)中。
    • 讓兩個(gè)基本操作 PushBack PopFront 能夠自己實(shí)現(xiàn)保護(hù)自己
    • 具體應(yīng)該怎么做呢?之前的我們對(duì)隊(duì)列模型中的 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;
    • 修改 newQueuedel_queue 里的初始化和銷(xiāo)毀關(guān)鍵段代碼。
    • 以及重點(diǎn)的 push_backpop_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;
          }   
  • 如此修改以后,該隊(duì)列模型就具備了初步的線程安全功能。
  • 在主代碼中,可以刪除 PopFrontPushBack 附近的保護(hù)操作。
  • 前方提到了,CRITICAL_SECTION 相對(duì)于 Mutex 不太安全,這里簡(jiǎn)單說(shuō)一下,具體請(qǐng)查詢相關(guān)資料
    • 前者只對(duì)當(dāng)前代碼段負(fù)責(zé),也就是其他操作這個(gè)資源的途徑是不被保護(hù)的。
    • 通俗的來(lái)說(shuō),假設(shè)有多個(gè)線程,CRITICAL_SECTION只保證在同一個(gè)"時(shí)間"內(nèi),只有一個(gè)線程能夠運(yùn)行這段代碼,假設(shè)我在其他代碼還有對(duì)這段代碼中的資源進(jìn)行訪問(wèn),那關(guān)鍵段就不能保證什么了。
    • 速度快開(kāi)銷(xiāo)小是因?yàn)樗蛢?nèi)核關(guān)系不大,是進(jìn)程內(nèi)的操作。
  • 發(fā)現(xiàn)問(wèn)題了嗎?
    • 在代碼中,對(duì)于empty 的操作存在著問(wèn)題,我們必須對(duì)它進(jìn)行類(lèi)似Mutex的保護(hù),而不是使用CRITICAL_SECTION
    • 我們這里應(yīng)該使用Mutex嗎?其實(shí)有一個(gè)更好的選擇,那就是在 Windows Vista之后引入的一個(gè)讀寫(xiě)鎖SRWLOCK,允許多個(gè)線程讀取數(shù)據(jù)或者單個(gè)線程寫(xiě)入數(shù)據(jù)
      • 為什么選擇它?道理還是一樣,因?yàn)樗皇褂脙?nèi)核資源。
      • 將代碼中對(duì)empty關(guān)鍵段保護(hù)修改或添加上SRWLOCK讀寫(xiě)鎖的保護(hù)
      • 操作并沒(méi)有什么區(qū)別,就是進(jìn)入保護(hù)區(qū)請(qǐng)求(AcquireSRWLock(Exclusive/Shared)),離開(kāi)保護(hù)區(qū)釋放(ReleaseSRWLock(Exclusive/Shared))。
      • 本來(lái)有一個(gè)更好的可以減小開(kāi)銷(xiāo)的 TryAcquire... 操作,但是確在Windows 7以后才引入,故不在此實(shí)現(xiàn)。

結(jié)后語(yǔ)

  • 所謂讀寫(xiě)鎖,并不是所謂的銀彈,意思就是不要盲目的使用讀寫(xiě)鎖,這里使用讀寫(xiě)鎖只是因?yàn)橄胍尤娴母采w知識(shí)點(diǎn)!
  • 要知道讀鎖的加持,并不一定就比一個(gè)互斥鎖(這是Linux平臺(tái)下對(duì)Windows臨界區(qū)的稱(chēng)呼)要廉價(jià),特別是在庫(kù)設(shè)計(jì)實(shí)現(xiàn)者手里,他必須考慮到種種因素,例如 寫(xiě)鎖餓死 現(xiàn)象,想要解決這個(gè)問(wèn)題,就不可避免的要犧牲讀鎖的性能,有可能將互斥鎖替換成讀寫(xiě)鎖以后,性能反而降低了。

寫(xiě)鎖餓死,是個(gè)挺廣泛的概念,只要有讀寫(xiě)鎖的身影就必定有它,可以查閱相關(guān)資料

  • 這一切都是需要測(cè)試,測(cè)試,再測(cè)試,之所以選擇在 Windows 平臺(tái)上開(kāi)發(fā),原因之一就是Visual Studio有一套強(qiáng)大到爆表的性能分析工具,你可以輕易找出代碼性能問(wèn)題。善用它來(lái)研究不同鎖之間的差別,性能。

  • 對(duì)于多線程程序而言,同步原語(yǔ)實(shí)際上還是要善用 條件變量/互斥鎖(臨界區(qū),關(guān)鍵段)這兩個(gè)概念,能滿足90% 的需求,最多再使用一些平臺(tái)關(guān)鍵字就行了,不要參雜著各種各樣的同步魔法,要不就換一種思維,除了 多線程,并發(fā)世界還有許多“很美好”的東西

很美好。。。是我自己說(shuō)的