1. 程式人生 > >[linux,c++] 基於mutex 的互斥訪問佇列實現

[linux,c++] 基於mutex 的互斥訪問佇列實現

實驗目的:

練習使用mutex 來保護需要互斥訪問物件,同時練習在linux下面使用autotools 來建立Makefile.am 檔案編寫。

練習將STL 中的 queue 與 linux 中的加鎖解鎖操作相互結合使用。

為後續的學習網路程式設計實現多個客戶端同時向伺服器端傳送請求訊息做鋪墊,本實驗中實現的互斥訪問佇列,

可以用作伺服器端為了接受來自多個客戶端的請求而開闢的緩衝區,即緩衝訊息相應佇列。

實驗環境:

Ubuntu 作業系統,g++ ,gcc 編譯器, autotools 系列工具<autoscan, aclocal, autoconf, autoheader, automake>

實驗程式碼:

1. mutexQueue.hpp

由於互斥訪問的佇列通常作為類中的成員變數,所以將它的實現方法直接寫到 hpp 檔案中。

這段程式碼的主要思想是將STL 中的佇列 queue 封裝到類mutexQueue 中,並且在類中為了實現對佇列中元素的互斥訪問,

增加了POSIX 中常用到的互斥量來進行加鎖。即每個想要訪問佇列中元素(訪問= 讀取 ; 修改 )的執行緒,

都首先需要申請_mutex, _mutex 是POSIX標準中定義的互斥量,原型是pthread_mutex_t . 

只有噹噹前的佇列不被任何執行緒訪問的時候,_mutex 才處於空閒可被申請的狀態。當執行緒成功申請到

互斥量_mutex 之後,

即可通過該互斥量對佇列進行加鎖,即呼叫POSIX中所定義的, pthread_mutex_lock (pthread_mutex_t *)來對互斥資源

(也稱作是臨界資源)進行加鎖,在加鎖操作之後,_mutex 即無法被其他執行緒申請

在加鎖期間申請佔用_mutex 的執行緒均會被至於阻塞狀態,直至當前佔用該佇列的執行緒釋放鎖,_mutex 被釋放,

此時之前由於申請佔用_mutex 的執行緒才會被從阻塞狀態喚醒,並對該_mutex 進行重新申請,若申請成功,

則通過_mutex 進行加鎖,加鎖之後獨自佔用互斥資源,申請失敗,繼續阻塞。

在這裡使用template 的方式來定義類mutexQueue 這樣使用者就可以像似使用普通的 STL queue 一樣向其中傳入定義

的複雜型別一樣使用 mutexQueue 所定義的物件了。

#include <queue>
#include <pthread.h>

template <typename Data>
class mutexQueue
{
private:
 std::queue<Data> _queue ;
 pthread_mutex_t _mutex ;

public :
 mutexQueue()
 {
   _mutex = PTHREAD_MUTEX_INITIALIZER ;
 }
 unsigned int size()
 {
  unsigned int s ;

  pthread_mutex_lock (&_mutex)  ;
  s =(unsigned int ) _queue.size()  ;
  pthread_mutex_unlock (&_mutex) ;
  return s ;
 }

 void push (Data const &data )
 {
  pthread_mutex_lock (&_mutex) ;
  _queue.push(data) ;
  pthread_mutex_unlock (&_mutex) ;
 }

 bool empty () const
 {
  bool res ;

  pthread_mutex_lock (&_mutex ) ;
  if ( _queue.size() == 0 )
     res =  true ;
  else
     res =  false ;
  pthread_mutex_unlock (&_mutex) ;

  return res ;
 }


 bool top ( Data &value )
 {
   /**
   here you should add the pthread_mutex_lock too!
  because during current thread visiting period  
  you can not make sure other one or more thread do something(pop , push)
  the change the size of the queue   2014/11/11 by Armin
   */
  if ( _queue.size() ==  0 )  
  {			
   return false ;<span>	</span>
  } 
  else
  {
   pthread_mutex_lock (&_mutex) ;
   value = _queue.front() ;
   pthread_mutex_unlock(&_mutex) ;
   return true ;
  }
 }
 void pop ()
 {
  if (_queue.size() != 0)
  {
   pthread_mutex_lock (&_mutex) ;
   _queue.pop() ;
   pthread_mutex_unlock (&_mutex) ;
  }
 }

} ;


//Main.cpp

在這段程式碼中所演示的就是,如何在程式中剛剛定義好的 mutexQueue 這個物件,不過,在本程式中並沒有建立多執行緒,

所以互斥訪問的效果根本看不出來。

這段程式碼,在第一次釋出部落格的時候錯誤的 copy 了//mutexQueue.hpp 的原始碼,在這裡更正一下!

//by Armin1027 2014/11/11

#include <iostream>
#include <string>
#include "mutexQueue.hpp"




using namespace std ;


int main ( int argc , char * args [] )
{
 string line ;
#include <iostream>
#include <string>
#include "mutexQueue.hpp"




using namespace std ;


int main ( int argc , char * args [] )
{
 string line ;
 mutexQueue<string> q ;
// cout<<"get size of q "<< q.size() <<endl ;
 cout<<"input string for queue insert "<<endl ;
 cin>>line ;
 q.push(line) ;
 cout<<"input string 2 for queue inserting "<<endl ;
 cin>>line ;
 q.push(line) ;
// q.push("the end") ;
 cout<<"now length of the queue is "<<q.size() <<endl ;


 for (int i = 0 ; i < q.size() ; i++ )
 {
  cout<<"length of q "<<q.size() <<endl ;
  q.top(line) ;
  q.pop() ;
  cout<<"content in q "<<line<<endl ;


 }


 return 0 ;


}         


編譯指令碼

g++  test.c  test.h  -o  test.exe

是我們在 linux/unix 下面 編寫 cpp 程式的時候最為常用的編譯命令,但是如果今後寫的程式從單個的檔案,

到一些列的檔案,並且等待編譯的檔案分佈在當前目錄下面的各個資料夾中,這種命令寫起來就很費勁了。

makefile 是linux 下面 用來組織(編譯,連線,最終生成可執行檔案 )c++專案的一種最為常用的一種編譯指令碼,

但是其中的語法規範很複雜,變動性很多,由於每個人都有著各自不同的書寫 makefile 的風格,所以makefile

的編寫規範還是閱讀性是 linux 初學者很難在短時間內理解,掌握,熟練應用的 。

GNU的牛人們為了彌補這種不足,開發出來一套規範的編譯工具,這一系列工具統稱是 autotools ,關於它的 相關說明

或是原理或者是安裝,可以自己去查相關資料,我就不加介紹了。

在這裡我要介紹的是,如何根據本實驗中的兩個檔案 mutexQueue.hpp Main.cpp

來編寫自己的Makefile檔案 

1.首先,將目錄切換到你所編寫的兩個檔案的所在目錄下面:

cd  thread_mutex/

ls => Main.cpp , mutexQueue.hpp

2. 輸入 autoscan 命令,得到的結果如下所示

new : autoconf.log , configure.scan 

old :  Main.cpp mutexQueue.hpp

3.將生成的 configure.scan 重新命名為 configure.in

mv configure.scan configure.in

4. 根據自己編寫的專案中原檔案的結構來修改configure.in 中的內容

修改前:


修改後:



5.修改之後如下圖所示,退出之後,分別按順序輸入命令

aclocal

autoconf

autoheader


6.編寫Makefile.am 檔案,這個檔案中定義了將要生成的makefile 中的規範

在這裡需要說明一點的就是,如果在不使用 autotools 的情況下,使用命令在隨後需要新增一條 -lpthread 

來表明需要使用到庫 pthread 中所定義的相關方法或是變數,相應的這一點在Makefile.am 中也是需要有所體現的,

所以就有了mQueue_LDADD=-lpthread 這個對應的是 pthread 庫中的相關呼叫,是作為靜態庫被引入的,

而後面的那個 _LDFLAGS = .. 說明的是 pthread 是作為動態庫被引入的。

靜態庫和動態庫就是,靜態庫是與程式進行繫結好的,比較佔記憶體容量,不過由於是事前繫結好

(”事前“,在這裡我還不太確定這個“事” 是編譯還是連結階段); 而動態連結,就是隻有在程式中需要使用的時候,

才將其與你所寫的程式進行連結,速度較慢,但是記憶體資源消耗很少。

bin_PROGRAMS= 名字是將要生成的可執行檔案的名字。


7. 輸入命令automake ,會對Makefile.am 進行解析生成 Makefile.in

   這個地方不得不說的是, automake 命令後面的 --add-missing 選項是必須要加上的(至少在本試驗中是這樣的,

  並且,這個 automake --add-missing 命令至少需要執行 2 次以上,知道不丟擲異常資訊為止,

  不過請注意,這裡我說的異常資訊,是由於專案中缺少相關的檔案,而這些檔案通過 --add-missing 引數隨著執行

  次數不斷的增多而新增到當前的專案中的,當然了,如果你寫的程式本身有問題或者是編譯檔案中存在問題的話,

   那帶 --add-missing 引數執行即便都得不到你想要的結果的)


 

automake 之後生成Makefile.in 


 輸入命令  ./configure , 如果正確執行的話會生成 Makefile , 這個就是我們編譯檔案生成的 Makefile了

8.如果前面的步驟執行正確的話,生成Makefile, 這時只需要輸入 make


即可讓程式自動編譯,生成最終在Makefile.am 中定義的bin_PROGRAMS = x

以 x 為名稱的可執行程式的

9.在當前的目錄中輸入  ./x 即可以使得程式得以執行 (綠色的 mQueue 即為所需要生成的可執行檔案 )


10, ./mQueue 執行該可執行檔案

 

如果不使用autotools 進行編譯的話,直接使用命令列來編譯這兩檔案也不難:

g++ Main.cpp mutexQueue.hpp -lpthread  -o Main  :這樣既可 。

因為我們在mutexQueue.hpp 中使用到的mutex 是 pthread.h 庫中的 pthread_mutex_t

所以在程式編譯之後,後期執行之前進行連結的時候是需要使用 pthread 庫中所定義的相關方法的,

所以需要指定一下 -lpthread (-l :link 在連線階段需要使用pthread.h 庫中的相關函式定義與實現)

不足及改進

1. 沒有建立多個執行緒來同時訪問,要在後續的程式碼中,定義函式指標來通過 POSIX 中的 pthread_t ,pthread_create(...)

等相關方法在Main 中啟動多個執行緒來實現互斥訪問互斥佇列。

2. 沒有實現程序間通訊,如果在程式中使用condition 相關執行緒通訊的POSIX 相關的函式的話,

可以試一試模擬生產者消費者之間的通訊問題從一對一到一對多,從而可以衍生出伺服器端與客戶端進行通訊的效果。

3. 在熟練掌握pthread_create(...)  和函式指標的的基礎上可以結合前一個實驗來實現同時建立兩個執行緒,

一個是 Server 另一個是 client 

使用相同的函式簽名 ,通過一個函式指標指向兩種呼叫。

這些想法可以在這幾天試著實驗一下。

相關推薦

[linuxc++] 基於mutex互斥訪問佇列實現

實驗目的: 練習使用mutex 來保護需要互斥訪問物件,同時練習在linux下面使用autotools 來建立Makefile.am 檔案編寫。 練習將STL 中的 queue 與 linux 中的加鎖解鎖操作相互結合使用。 為後續的學習網路程式設計實現多個客戶端同時向伺服

C++基於模版的迴圈佇列實現

近期因為要反反覆覆使用佇列,而佇列需要儲存的元素格式又千差萬別,在網上搜了下貌似雙邊佇列可以解決這個問題,但是效率有點低。於是自己寫了個基於模版的迴圈佇列實現方式,有任何不合理之處還請各位大牛輕怕。 #pragma once template<class T>

synchronized修飾方法保證資料同步準確性限制執行緒互斥訪問

1.未加synchronized關鍵,造成訪問順序混亂 package thread; /** * @author [email protected] created on 20

windows下多程序通訊基於共享記憶體環形佇列實現

1 #include "stdafx.h" 2 #include "InterProcessCommunication.h" 3 #include <string> 4 enum 5 { 6 STATE_EMPTY = 0, 7 STATE_READ,

C# 基於NPOI+Office COM元件 實現20行程式碼線上預覽文件(wordexcelpdftxtpng)

由於專案需要,需要一個線上預覽office的功能,小編一開始使用的是微軟提供的方法,簡單快捷,但是不符合小編開發需求, 就另外用了:將檔案轉換成html檔案然後預覽html檔案的方法。對微軟提供的方法感興趣的小夥伴可以去看一下,夠簡單直接:word+excle+pdf表格線上瀏覽 我們來說一下小編使用的方法,

C#基於SQLiteHelper類似SqlHelper類實現存取Sqlite資料庫的方法

本文例項講述了C#基於SQLiteHelper類似SqlHelper類實現存取Sqlite資料庫的方法。分享給大家供大家參考。具體如下: 這個類不是我實現的,英文原文地址為http://www.eggheadcafe.com/articles/20050315.asp,這裡修改了原文中分析sql語句

基於連結串列的佇列實現

1.建立鏈節點類link 只有一種資料int型別,和對下一個鏈節點的引用next public class Link { public int a; public Link next; public Link(int m){ a=m; }

使用 elasticsearch、LogStash、Kibana完成網站流量的監控系統(基於nginx的訪問日誌實現流量監控)

分散式帶來的變革:     多節點、日誌分散、運維成本高 先看幾個實際的案例。     各自的解決方案     一些比較主流的集中式日誌管理系統      簡單的Rsyslog      商業化的 Splunk      開源的有 Facebook 公司的

C語言基數排序——順序佇列實現

基數排序 基本要求: 從鍵盤上輸入n個程度為m的整數,要求輸出這些整數的升序排列。 具體要求: 使用的資料結構是佇列,利用順序佇列來實現 有良好的人機互動 能夠輸出每一趟分配和收集的情況 基本概念: 基數排序屬於分配式排序、又稱桶子法。通過鍵值的查詢,

C#基於RSA加密算法實現軟件註冊實戰演練

名稱 時間 一起 問題 load 靈活 width 如何實現 rsa加密算法 一、課程介紹 本次分享課程屬於《C#高級編程實戰技能開發寶典課程系列》中的一部分,阿笨後續會計劃將實際項目中的一些比較實用的關於C#高級編程的技巧分享出來給大家進行學習,不斷的收集、整理和完

C++ 開發基於Linux好還是Windows 好?

我想故事的發展是這樣.... 先是糾結語言 (lisp沒聽過 聽說python效率不高還縮進 原來ruby是小鬼子弄的 那個什麽叫lua的只能用來寫遊戲腳本 放眼望去java只能做民工啊 那個c語言土掉渣, 過時幾百年了

c/c++ linux 進程間通信系列7使用pthread mutex

shm delete clu wait 進程間通信 pro -m printf gre linux 進程間通信系列7,使用pthread mutex #include <stdio.h> #include <stdlib.h> #include &

c/c++ linux 程序間通訊系列7使用pthread mutex

linux 程序間通訊系列7,使用pthread mutex #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/shm.h> #include <pthr

最簡單的實現Linux C++多執行緒的互斥訪問

#include <stdlib.h> #include <string.h> #include <iostream> #include <unistd.h> #include <errno.h> #include <pthrea

Linux c 基於記憶體的程序通訊—共享記憶體、共享佇列(訊息佇列

基於記憶體的程序通訊: 1.      核心共享記憶體 程式設計模型:  1.1.建立共享記憶體,得到一個ID  shmget 1.2.把ID影射成虛擬地址(掛載)  shmat        1.3.使用虛擬地址訪問核心共享記憶體使用任何記憶體函式與運算子號       

linux ctrl+cctrl+zctrl+d

get http ont detail ctrl+c 繼續 後臺進程 知識庫 當前 轉自:http://blog.csdn.net/u012787436/article/details/39722583 ctrl+c(中斷)、ctrl+z(掛起)和ctrl+d(EO

清華大學視頻課件:基於LinuxC++(自主模式)

清華大學 視頻課件 基於linux的c++基於Linux的C++(自主模式)課程簡介Linux操作系統開源的特性使得其獲得越來越重要的地位,而Linux系統編程也向C++程序設計者提出了更高的要求。本課程由C/C++語言的共性與特性出發,在深入學習程序設計語言的基礎上,進一步強調程序設計語言的適用性,並與Li

Linux學習命令匯總九——任務計劃調度atdcrond及文件訪問控制列表

atd crontab linux任務計劃 facl 文件訪問控制列表 本章Blog相關Linux知識點linux 任務計劃: 一次性任務計劃命令: at ,batch ,依賴進程atd 周期性任務計劃命令:crontab ,anacron ,依賴進程crondat,batc

Linux中安裝MongoDBMongoDB開啟遠程訪問和設置管理員賬戶

-c 安裝 方便 新建 新博 相關 mongo window .config 寫在前面: 好久沒更更新博客了,主要因為我現在在頭條寫博客文章。大家可以關註下我的頭條號:我是樂樂樂樂呀 之前寫過在windows環境下安裝MongoDB,同時也寫了個在windows環境下用

redis在Linux虛擬機器上安裝了在windows下無法訪問的問題

redis在Linux虛擬機器上安裝了,在windows下無法訪問的問題 1:ifconfig檢視虛擬機器分配的ip 2:redis.conf中bind 指定虛擬機器的ip 3:redis-server …/redis.comf 參考了一些網上的資料,主要的步驟是: 1.window