⑴ 分析怎樣實現的對共享存儲區的互斥和同步
你說的這個是遠程監控和備份,需要在PC1上登錄客戶端軟體通過花生殼或其他域名伺服器域名解析出去,然後你在PC2上面通過解析出來的域名登錄上去進行監控和存儲即可。不過遠程監控效果很一般,圖像也不連續,除非你是光線上網這樣才會好一點。
⑵ 計算機操作系統知識點
計算機操作系統知識點
網路的神奇作用吸引著越來越多的用戶加入其中,正因如此,網路的承受能力也面臨著越來越嚴峻的考驗―從硬體上、軟體上、所用標准上......,各項技術都需要適時應勢,對應發展,這正是網路迅速走向進步的催化劑。下面是關於計算機操作系統知識點,希望大家認真閱讀!
4.1.1操作系統的概念
操作系統:是管理計算機軟硬體資源的程序,同時它又是用戶與計算機硬體的介面。
4.1.2操作系統的構成
進程管理、內存管理、文件管理、輸入/輸出系統管理、二級存儲管理、聯網、保護系統、命令解釋程序
4.2.1操作系統的類別
經過多年的發展,操作系統多種多樣。為提高大型計算機系統的資源利用率,操作系統從批處理,多道程序發展為分時操作系統。為了滿足計算機處理實時事件的需要,就有實時操作系統。為適應個人計算機系統的需要又出現了桌面操作系統。為適應並行系統的需要,就有了多處理器操作系統。為滿足網路和分布計算的需要,就有了網路操作系統和分布式操作系統。此外,還有為支持嵌入式計算機的嵌入式操作系統。
4.2.2計算環境
從計算機誕生至今,操作系統總是與具體的計算環境相聯系,它總是在某種計算環境中設置和使用,就目前來看計算環境可分為以下幾類:
1.傳統計算環境
指普通意義下的獨立或聯網工作的通用計算機所形成的計算環境。
2.基於Web的計算環境
互聯網的普及使得計算被延伸到Web環境。
3.嵌入式計算環境
嵌入式計算機就是安裝在某些設備上的計算部件,其計算相對比較簡單。
4.3.1進程的概念
什麼是進程?它與程序有什麼區別?
程序:用戶為完成某一個特定問題而編寫的操作步驟。
進程:可以簡單地被看作是正在執行的程序。但是進程需要一定的資源來完成它的任務(例如CPU時間、內存、文件和I/O設備)。
進程與程序的區別在於進程是動態的、有生命力的,而程序是靜態的。一個程序載入到內存,系統就創建一個進程,程序執行結束後,該進程也就消亡了。
在計算機中,由於多個程序共享系統資源,就必然引發對CPU的爭奪。如何有效地利用CPU資源,如何在多個請求CPU的進程中選擇取捨,這就是進程管理要解決的問題。
4.3.3進程式控制制塊PCB(略)
為了控制進程,操作系統就必須知道進程存儲在哪裡,以及進程的一些屬性。
進程式控制制塊是進程實體的一部分,是操作系統中記錄進程的專用數據結構。一個新的進程創建時,操作系統就會為該進程建立一個進程式控制制塊。操作系統根據進程式控制制塊對並發進程進行控制。
4.3.4進程調度及隊列圖
計算機採用多道程序的目的是使得計算機系統無論何時都有進程運行,單處理器的計算機在某一時刻CPU只能運行一個進程,如果存在多個進程,其它進程就需要等待CPU空閑時才能被調度執行。
當一個進程處於等待或CPU時間片用完時,操作系統就會從該進程中拿走CPU控制權,然後再交給其它進程使用,這就是進程的調度。
4.3.5CPU調度及其准則
在設計CPU調度程序時主要應該考慮的准則包括:
(1)CPU使用率。讓CPU盡可能地忙。
(2)吞吐量。讓CPU在一定時間內完成的進程數盡可能多。
(3)周轉時間。讓進程從提交到運行完成的時間盡可能短。
(4)等待時間。讓進程在就緒隊列中等待所花時間之和盡可能短。
(5)響應時間。讓進程從提交請求到產生第一響應之間的時間盡可能短。
主要的CPU調度演算法
1、先到先服務
2、最短作業優先
3、優先權
4、輪轉
5、多級隊列
6、多級反饋隊列
4.3.7進程的同步與互斥
進程的同步就是指相互協作的進程不斷調整它們之間的相對速度,以實現共同有序地推進。
換句話說,在操作系統中,允許多個進程並發運行。然而,有些進程之間本身存在某種聯系,它們在系統中需要一種協作,以保證進程能正確有序地執行並維護數據的一致性。
在操作系統中,可能存在著多個進程。而系統中一些資源一次只允許一個進程使用,這類資源被稱為臨界資源。在進程中訪問臨界資源的那段程序稱為臨界區。當一個進程進入臨界區執行時,其它進程就不允許進入臨界區執行,否則就會導致錯誤結果。由此得出:
多個進程並發執行時,只允許一個進程進入臨界區運行,這就是進程的互斥。
例如:多個進程在競爭使用列印機時表現為互斥。
一個文件可供多個進程共享,其中有一個進程在寫操作時,其它進程則不允許同時寫或讀,表現為互斥。
4.3.8進程的死鎖及處理方法
在多道程序設計中,多個進程可能競爭一定數量的資源。一個進程在申請資源時,如果所申請資源不足,該進程就必須處於等待狀態。如果所申請的資源被其它進程佔有,那麼進程的等待狀態就可能無法改變,從而形成進程之間相互一直等待的局面,這就是死鎖。
競爭資源引起死鎖
引起死鎖的四個必要條件:
互斥:任一時刻只能有一個進程獨占某一資源,若另一進程申請該資源則需延遲到該資源釋放為止。
佔有並等待:即該進程佔有部分資源後還在等待其它資源,而該資源被其它進程佔有。
非搶占:某進程已佔用資源且不主動放棄它所佔有的資源時,其它進程不能強占該資源,只有等其完成任務並釋放資源。
循環等待:在出現死鎖的系統中,一定存在這樣一個進程鏈,其中每個進程至少佔有其它進程所必需的資源,從而形成一個等待鏈。
處理死鎖問題的三種方式:
可使用協議預防和避免死鎖,確保系統從不會進入死鎖狀態。
可允許系統進入死鎖狀態,然後檢測出死鎖狀態,並加以恢復。
可忽略進程死鎖問題,並假裝系統中死鎖從來不會發生。即沒有必要把精力花在小概率事件上。
處理死鎖優先考慮的順序:先預防和避免再檢測和恢復
4.4內存管理
內存是現代操作系統的核心。內存用於容納操作系統和各種用戶進程,是可以被CPU和I/O設備所共同訪問的數據倉庫。計算機的所有程序運行時都要調入內存。
內存管理的主要工作是:為每個用戶進程合理地分配內存,以保證各個進程之間在存儲區不發生沖突;當內存不足時,如何把內存和外存結合起來,給用戶提供一個比實際內存大得多的虛擬內存,使得程序能順利執行。內存管理包括內存分配、地址映射、內存保護和擴充。
4.4.1用戶程序執行與地址映射
用戶編寫程序在執行前,需要多個處理步驟,這些步驟可將源程序轉變為二進制機器代碼,然後在內存中等待執行。當然有時並非每個步驟都是必需的。
通常,將指令和數據的.地址映射成內存地址可以發生在以下三個執行階段。(了解)
1.編譯階段:如果在編譯時就知道進程將在內存中的什麼位置駐留,那麼編譯器就可以直接以生成絕對地址代碼。
2.載入階段:不知道進程將駐留在什麼位置,那麼編譯器就必須生成程序的邏輯地址,在載入階段再轉變成內存的絕對地址。
3.執行階段:如果進程在執行時可以從一個內存段移動到另一個內存段,那麼進程的絕對地址映射工作只能延遲到執行時進行。
4.4.2物理地址空間與邏輯地址空間
物理地址:是計算機內存單元的真實地址。
物理地址空間:由物理地址所構成的地址范圍。
邏輯地址:用戶程序地址,從0開始編址。
邏輯地址空間:由邏輯地址所構成的地址范圍。
地址映射:用戶程序在運行時要裝入內存,這就需要將邏輯地址變換成物理地址,這個過程稱為地址映射,也稱重定位。
用戶編寫的源程序是不考慮地址的,源程序經CPU編譯後產生邏輯地址。從CPU產生的邏輯地址轉換為內存中的物理地址的映射是由計算機中被稱為內存管理單元的硬體設備來實現的,將邏輯地址與內存管理單元中存放的內存基址相加就得到了物理地址。
4.4.3進程使用內存的交換技術
為了更加有效地使用內存,進程在不運行時,可以暫時從內存移至外存上,直到需要再運行時再重新調回到內存中。也就是說內存管理程序可將剛剛運行過的進程從內存中換出以釋放出佔用的內存空間,然後將另一個要運行的進程占據前者釋放的內存空間。
計算機工作時,為了將多個進程放入到內存就必須考慮在內存中如何放置這些進程。
4.4.4內存分配方案-連續
對於連續內存分配方案,開始時所有內存是一個大的孔,隨著內存分配的進行就會形成位置上不連續的大小不一的孔。在連續內存分配方案中,當新進程需要內存時,為其尋找合適的孔,實現內存分配。該方案為每個進程所分配的內存物理地址空間在位置上是連續的。
4.4.5內存分配方案-分頁式
分頁管理基本思想:
o內存物理地址空間劃分為若干個大小相等的塊(頁框)
o進程的邏輯地址空間也劃分為同樣大小的塊(頁面)
o內存分配時每個頁面對應地分配一個頁框,而一個進程所分得頁框在位置上不必是連續的。
頁表:操作系統為每個用戶程序建立一張頁表,該表記錄用戶程序的每個邏輯頁面存放在哪一個內存物理頁框。
4.5虛擬內存方案
虛擬內存是一個容量很大的存儲器的邏輯模型,它不是任何實際的物理存儲器,它一般是藉助硬碟來擴大主存的容量。
虛擬內存:對於一個進程來講,如果僅將當前要運行的幾個頁面裝入內存便可以開始運行,而其餘頁面可暫時留在磁碟上,待需要時再調入內存,並且調入時也不佔用新的內存空間,而是對原來運行過的頁面進行置換。這樣,就可以在計算機有限的內存中同時駐留多個進程並運行。而對用戶來講感覺到系統提供了足夠大的物理內存,而實際上並非真實的,這就是虛擬內存。
4.5.2頁面請求與頁面置換演算法
頁面請求:在虛擬內存技術中,進程運行時並沒有將所有頁面裝入到內存,在運行過程中進程會不斷地請求頁面,如果訪問的頁面已在內存,就繼續執行下去;但如果要訪問的頁面尚未調入到內存,便請求操作系統將所缺頁面調入內存,以便進程能繼續運行下去。
頁面置換:如果請求頁面調入內存時,分配給該進程的頁框已用完,就無法立即裝入所請求頁面。此時,必須將進程中的某個頁面從內存的頁框調出到磁碟上,再從磁碟上將所請求的頁面調入到內存的該頁框中。這個過程叫做頁面置換。
4.6文件管理
文件管理是操作系統最常見的組成部分。文件管理主要提供目錄及其文件的管理。
4.6.1文件的概念
文件:保存在外部存儲設備上的相關信息的集合。
文件命名:文件主名+擴展名
文件存取屬性:
只讀:只允許授權用戶進行讀操作。
讀寫:只允許授權用戶進行讀和寫的操作。
文檔:允許任何用戶進行讀寫操作。
隱藏:不允許用戶直接看到文件名。
文件系統:是對文件進行操作和管理的軟體,是用戶與外存之間的介面。這個系統將所有文件組織成目錄結構保存在外存,一個文件對應其中的一個目錄條。目錄條記錄有文件名、文件位置等信息。
操作系統對文件的基本操作包括:
創建文件、文件寫、文件讀、文件重定位、文件刪除、文件截短。
對文件的其它操作包括:文件復制、重命名、更改屬性等。
;⑶ 編譯器如何處理多線程程序
這是一個多線程例子,裡面只有兩個線程,是生產者/消費者模式,已編譯通過,注釋很詳細,
如下:
/* 以生產者和消費者模型問題來闡述Linux線程的控制和通信你
生產者線程將生產的產品送入緩沖區,消費者線程則從中取出產品。
緩沖區有N個,是一個環形的緩沖池。
*/
#include <stdio.h>
#include <pthread.h>
#define BUFFER_SIZE 16
struct prodcons
{
int buffer[BUFFER_SIZE];/*實際存放數據的數組*/
pthread_mutex_t lock;/*互斥體lock,用於對緩沖區的互斥操作*/
int readpos,writepos; /*讀寫指針*/
pthread_cond_t notempty;/*緩沖區非空的條件變數*/
pthread_cond_t notfull;/*緩沖區未滿 的條件變數*/
};
/*初始化緩沖區*/
void pthread_init( struct prodcons *p)
{
pthread_mutex_init(&p->lock,NULL);
pthread_cond_init(&p->notempty,NULL);
pthread_cond_init(&p->notfull,NULL);
p->readpos = 0;
p->writepos = 0;
}
/*將產品放入緩沖區,這里是存入一個整數*/
void put(struct prodcons *p,int data)
{
pthread_mutex_lock(&p->lock);
/*等待緩沖區未滿*/
if((p->writepos +1)%BUFFER_SIZE ==p->readpos)
{
pthread_cond_wait(&p->notfull,&p->lock);
}
p->buffer[p->writepos] =data;
p->writepos++;
if(p->writepos >= BUFFER_SIZE)
p->writepos = 0;
pthread_cond_signal(&p->notempty);
pthread_mutex_unlock(&p->lock);
}
/*從緩沖區取出整數*/
int get(struct prodcons *p)
{
int data;
pthread_mutex_lock(&p->lock);
/*等待緩沖區非空*/
if(p->writepos == p->readpos)
{
pthread_cond_wait(&p->notempty ,&p->lock);//非空就設置條件變數notempty
}
/*讀書據,移動讀指針*/
data = p->buffer[p->readpos];
p->readpos++;
if(p->readpos == BUFFER_SIZE)
p->readpos = 0;
/*設置緩沖區未滿的條件變數*/
pthread_cond_signal(&p->notfull);
pthread_mutex_unlock(&p->lock);
return data;
}
/*測試:生產站線程將1 到1000的整數送入緩沖區,消費者線程從緩沖區中獲取整數,兩者都列印信息*/
#define OVER (-1)
struct prodcons buffer;
void *procer(void *data)
{
int n;
for( n=0;n<1000;n++)
{
printf("%d ------>\n",n);
put(&buffer,n);
}
put(&buffer,OVER);
return NULL;
}
void *consumer(void *data)
{
int d;
while(1)
{
d = get(&buffer);
if(d == OVER)
break;
else
printf("----->%d\n",d);
}
return NULL;
}
int main()
{
pthread_t th_p,th_c;
void *retval;
pthread_init(&buffer);
pthread_create(&th_p,NULL,procer,0);
pthread_create(&th_c,NULL,consumer,0);
/*等待兩個線程結束*/
pthread_join(th_p, &retval);
pthread_join(th_c,&retval);
return 0;
}
⑷ java多線程開發的同步機制有哪些
Java同步
標簽: 分類:
一、關鍵字:
thread(線程)、thread-safe(線程安全)、intercurrent(並發的)
synchronized(同步的)、asynchronized(非同步的)、
volatile(易變的)、atomic(原子的)、share(共享)
二、總結背景:
一次讀寫共享文件編寫,嚯,好傢伙,竟然揪出這些零碎而又是一路的知識點。於是乎,Google和翻閱了《Java參考大全》、《Effective Java Second Edition》,特此總結一下供日後工作學習參考。
三、概念:
1、 什麼時候必須同步?什麼叫同步?如何同步?
要跨線程維護正確的可見性,只要在幾個線程之間共享非 final 變數,就必須使用 synchronized(或 volatile)以確保一個線程可以看見另一個線程做的更改。
為了在線程之間進行可靠的通信,也為了互斥訪問,同步是必須的。這歸因於java語言規范的內存模型,它規定了:一個線程所做的變化何時以及如何變成對其它線程可見。
因為多線程將非同步行為引進程序,所以在需要同步時,必須有一種方法強制進行。例如:如果2個線程想要通信並且要共享一個復雜的數據結構,如鏈表,此時需要
確保它們互不沖突,也就是必須阻止B線程在A線程讀數據的過程中向鏈表裡面寫數據(A獲得了鎖,B必須等A釋放了該鎖)。
為了達到這個目的,java在一個舊的的進程同步模型——監控器(Monitor)的基礎上實現了一個巧妙的方案:監控器是一個控制機制,可以認為是一個
很小的、只能容納一個線程的盒子,一旦一個線程進入監控器,其它的線程必須等待,直到那個線程退出監控為止。通過這種方式,一個監控器可以保證共享資源在
同一時刻只可被一個線程使用。這種方式稱之為同步。(一旦一個線程進入一個實例的任何同步方法,別的線程將不能進入該同一實例的其它同步方法,但是該實例
的非同步方法仍然能夠被調用)。
錯誤的理解:同步嘛,就是幾個線程可以同時進行訪問。
同步和多線程關系:沒多線程環境就不需要同步;有多線程環境也不一定需要同步。
鎖提供了兩種主要特性:互斥(mutual exclusion) 和可見性(visibility)。
互斥即一次只允許一個線程持有某個特定的鎖,因此可使用該特性實現對共享數據的協調訪問協議,這樣,一次就只有一個線程能夠使用該共享數據。
可見性要更加復雜一些,documents它必須確保釋放鎖之前對共享數據做出的更改對於隨後獲得該鎖的另一個線程是可見的 —— 如果沒有同步機制提供的這種可見性保證,線程看到的共享變數可能是修改前的值或不一致的值,這將引發許多嚴重問題
小結:為了防止多個線程並發對同一數據的修改,所以需要同步,否則會造成數據不一致(就是所謂的:線程安全。如java集合框架中Hashtable和
Vector是線程安全的。我們的大部分程序都不是線程安全的,因為沒有進行同步,而且我們沒有必要,因為大部分情況根本沒有多線程環境)。
2、 什麼叫原子的(原子操作)?
Java原子操作是指:不會被打斷地的操作。(就是做到互斥 和可見性?!)
那難道原子操作就可以真的達到線程安全同步效果了嗎?實際上有一些原子操作不一定是線程安全的。
那麼,原子操作在什麼情況下不是線程安全的呢?也許是這個原因導致的:java線程允許線程在自己的內存區保存變數的副本。允許線程使用本地的私有拷貝進
行工作而非每次都使用主存的值是為了提高性能(本人愚見:雖然原子操作是線程安全的,可各線程在得到變數(讀操作)後,就是各自玩
弄自己的副本了,更新操作(寫操作)因未寫入主存中,導致其它線程不可見)。
那該如何解決呢?因此需要通過java同步機制。
在java中,32位或者更少位數的賦值是原子的。在一個32位的硬體平台上,除了double和long型的其它原始類型通常都
是使用32位進行表示,而double和long通常使用64位表示。另外,對象引用使用本機指針實現,通常也是32位的。對這些32位的類型的操作是原
子的。
這些原始類型通常使用32位或者64位表示,這又引入了另一個小小的神話:原始類型的大小是由語言保證的。這是不對的。java語言保證的是原始類型的表
數范圍而非JVM中的存儲大小。因此,int型總是有相同的表數范圍。在一個JVM上可能使用32位實現,而在另一個JVM上可能是64位的。在此再次強
調:在所有平台上被保證的是表數范圍,32位以及更小的值的操作是原子的。
3、 不要搞混了:同步、非同步
舉個例子:普通B/S模式(同步)AJAX技術(非同步)
同步:提交請求->等待伺服器處理->處理完返回 這個期間客戶端瀏覽器不能幹任何事
非同步:請求通過事件觸發->伺服器處理(這是瀏覽器仍然可以作其他事情)->處理完畢
可見,彼「同步」非此「同步」——我們說的java中的那個共享數據同步(synchronized)
一個同步的對象是指行為(動作),一個是同步的對象是指物質(共享數據)。
4、 Java同步機制有4種實現方式:(部分引用網上資源)
① ThreadLocal ② synchronized( ) ③ wait() 與 notify() ④ volatile
目的:都是為了解決多線程中的對同一變數的訪問沖突
ThreadLocal
ThreadLocal 保證不同線程擁有不同實例,相同線程一定擁有相同的實例,即為每一個使用該變數的線程提供一個該變數值的副本,每一個線程都可以獨立改變自己的副本,而不是與其它線程的副本沖突。
優勢:提供了線程安全的共享對象
與其它同步機制的區別:同步機制是為了同步多個線程對相同資源的並發訪問,是為了多個線程之間進行通信;而 ThreadLocal 是隔離多個線程的數據共享,從根本上就不在多個線程之間共享資源,這樣當然不需要多個線程進行同步了。
volatile
volatile 修飾的成員變數在每次被線程訪問時,都強迫從共享內存中重讀該成員變數的值。而且,當成員變數發生變化時,強迫線程將變化值回寫到共享內存。
優勢:這樣在任何時刻,兩個不同的線程總是看到某個成員變數的同一個值。
緣由:Java
語言規范中指出,為了獲得最佳速度,允許線程保存共享成員變數的私有拷貝,而且只當線程進入或者離開同步代碼塊時才與共享成員變數的原
始值對比。這樣當多個線程同時與某個對象交互時,就必須要注意到要讓線程及時的得到共享成員變數的變化。而 volatile
關鍵字就是提示 VM :對於這個成員變數不能保存它的私有拷貝,而應直接與共享成員變數交互。
使用技巧:在兩個或者更多的線程訪問的成員變數上使用 volatile 。當要訪問的變數已在 synchronized 代碼塊中,或者為常量時,不必使用。
線程為了提高效率,將某成員變數(如A)拷貝了一份(如B),線程中對A的訪問其實訪問的是B。只在某些動作時才進行A和B的同步,因此存在A和B不一致
的情況。volatile就是用來避免這種情況的。
volatile告訴jvm,它所修飾的變數不保留拷貝,直接訪問主內存中的(讀操作多時使用較好;線程間需要通信,本條做不到)
Volatile 變數具有 synchronized 的可見性特性,但是不具備原子特性。這就是說線程能夠自動發現 volatile
變數的最新值。Volatile
變數可用於提供線程安全,但是只能應用於非常有限的一組用例:多個變數之間或者某個變數的當前值與修改後值
之間沒有約束。
您只能在有限的一些情形下使用 volatile 變數替代鎖。要使 volatile 變數提供理想的線程安全,必須同時滿足下面兩個條件:
對變數的寫操作不依賴於當前值;該變數沒有包含在具有其他變數的不變式中。
sleep() vs wait()
sleep是線程類(Thread)的方法,導致此線程暫停執行指定時間,把執行機會給其他線程,但是監控狀態依然保持,到時後會自動恢復。調用sleep不會釋放對象鎖。
wait是Object類的方法,對此對象調用wait方法導致本線程放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象發出notify方法(或notifyAll)後本線程才進入對象鎖定池准備獲得對象鎖進入運行狀態。
(如果變數被聲明為volatile,在每次訪問時都會和主存一致;如果變數在同步方法或者同步塊中被訪問,當在方法或者塊的入口處獲得鎖以及方法或者塊退出時釋放鎖時變數被同步。)