您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“并行Shell腳本如何驗證Linux的互斥信號量”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“并行Shell腳本如何驗證Linux的互斥信號量”這篇文章吧。
1 Linux下的互斥信號量的使用
1)Linux下互斥信號量的作用
互斥信號量主要是用于訪問共享資源時保證操作的原子性,即為一個整體的動作不允許被打斷。
2)Linux下的文件操作函數的學習方式
man命令學習函數使用,寫一個小代碼,將函數用起來。
下面就帶大家學習下互斥信號量相關的函數,然后用代碼將這些函數串聯起來,并用并行腳本進行一下驗證。
2 Linux下互斥信號量相關的函數
1)ftok函數
ftok函數用于構造鍵值。
① 函數原型。
key_t ftok( char * fname, int id )
② 頭文件。
include <sys/types.h> include <sys/ipc.h>
③ 參數。
fname:文件名在內核中的一種數字表示。
id:項目id號。
鍵值有fname和項目id號組合產生。
④ 返回值。
成功:返回產生的鍵值。
失敗:-1。
2)semget函數
semget函數用于創建打開信號量。
① 函數原型。
int semget(key_t key,int nsems,int semflg)
獲取信號量集合的標示符。
當key所指定的信號量不存在的時候,并且semflg里包含了IPC_CREAT,這個時候,就會創建一個信號量集。
② 頭文件。
include <sys/types.h> include <sys/ipc.h> include <sys/sem.h>
③ 參數。
key:鍵值。
semflay:標志,可以去IPC_CREAT,對應鍵值的信號量如果不存在還可以創建信號量。
nsems:創建的這個信號量集合里面包含的信號量數目。
④ 返回值。
成功:返回信號量集合的標示符。
失敗:-1。
3)semctl函數
semctl函數在一個信號量集或集合中的單個信號量上執行各種控制操作。
① 函數原型。
int semctl(int semid, int semnum, int cmd,.../* union semun arg*/)
② 頭文件。
include <sys/types.h> include <sys/ipc.h>
③ 參數。
semid:要控制的信號量集合的標示符。
semnum:用于標識集合中的具體信號量。
cmd:指定了需執行的操作。
信號量參數枚舉如下:
union semun { int val; // SETVAL的值 struct semid_ds *buf; // IPC_STAT, IPC_SET的緩沖 unsigned short *array; // GETALL, SETALL的數值 struct seminfo *__buf; // IPC_INFO的緩沖 };
信號量集合結構體如下:
struct semid_ds { struct ipc_perm sem_perm; // 權限 time_t sem_otime; // 上次semop的時間 time_t sem_ctime; // 上次修改的時間 unsigned long sem_nsems; // 信號量集中信號量個數 };
參數說明如下。
<1 常規控制操作.
加入下面參數進行操作都會忽略semnum參數。
IPC_RMID:立即刪除信號量集及其關聯的semid_ds數據結構。
IPC_STAT:在arg.buf指向的緩沖器中放置一份與這個信號量集相關聯的semid_ds數據結構的副本。
IPC SET:使用arg.buf指向的緩沖器中的值來更新與這個信號量集相關聯的semid_ds數據結構中選中的字段。
<2 獲取和初始化信號量值。
下面的操作可以獲取或初始化一個集合中的單個或所有信號量的值。獲取一個信號量的值需具備在信號量上的讀權限,而初始化該值則需要寫權限。
GETVAL:semctl返回由semid指定的信號量集中第semmum個信號量的值。這個操作無需arg參數。
SETVAL:將由semid指定的信號量集中第semnum個信號量的值初始化arg.val。
GETALL:獲取由semid指向的信號量集中所有信號量的值并將它們放arg.array指向的數組中。
SETALL:使用arg.array指向的數組中的值初始化semid指向的集合中的所有信號量。這個操作將忽略semnum參數。
注意GETVAL和GETALL返回的信息在調用進程使用它們時可能已經過期了。
<3 獲取單個信號量的信息。
下面的操作返回semid引用的集合中第semnum個信號量的信息。所有這些操作都需要在信號量集合中具備讀權限,并且無需arg參數。
GETPID:返回上一個在該信號量上執行semopO的進程的進程ID,這個值被稱為sempid值。如果還沒有進程在該信號量上執行過semopO,那么就返回0。
GETNCNT:返回當前等待該信號量的值增長的進程數,這個值被稱為semncnt值。
GETZCNT:返回當前等待該信號量的值變成0的進程數;這個值被稱為semzcnt值。
與上面介紹的GETVAL和GETALL操作一樣,GETPID、GETNCNT以及GETZCNT操作返回的信息在調用進程使用它們時可能已經過期了。
④ 返回值。
成功:semctl返回的值取決于cmd,如下。
GETVAL:semval的值。
GETPID:sempid的值。
GETNCNT:semncnt的值。
GETZCNT:semzcnt的值。
其他參數:返回0。
否則,semctl返回-1,并設置errno以指示錯誤。
4)semop函數
semop函數用于操作信號量集合中的信號量。
① 函數原型。
int semop(int semid, struct sembuf *sops, unsigned nsops)
② 頭文件。
include <sys/types.h> include <sys/ipc.h> include <sys/sem.h>
③ 參數。
semid:要操作的信號量集合的標示符。
nsops:要操作多少個信號量。
sops:對信號量執行什么樣的操作,執行什么操作由struct sembuf這一結構中量決定。
struct sembuf{ unsigned short sem_num; // 信號量的數量 short sem_op; // 要執行的操作 short semf1g; // 操作標志(IPC_NOMAIT和SEM_UNDO) }
當sem_op > 0時,將信號量的值加上sem_op的值。
其結果是:其他等待減小信號量值的進程可能會被喚醒并執行它們的操作。(需要寫權限)
當sem_op < 0時,將信號量的值減去sem_op的值。
如果信號量的當前值大于或等于sem_op的絕對值,那么操作會立即結束。否則semop會阻塞直到信號量值增長到在執行操作之后不會導致出現負值的情況為止。(需要寫權限)
當sem_op = 0時,就對信號量值進行檢查以確定它當前是否等于0。如果等于0,那么操作將立即結束,否則semop就會阻塞直到信號量值變成0為止。(需要讀權限)
④ 返回值。
成功:0。
失敗:-1。
3 實例代碼
下面用一個小程序用一下上面介紹的幾個函數。
1)程序原理
首先,通過并行腳本同時運行程序,在不加入互斥信號量的時候,不應該被分開的程序會被打斷(插入)。
接著,加入互斥信號量,此時并行程序每個程序都不會被另一個程序打斷(插入)。
2)未加入信號量的情況
下面的頭文件有些是不必要的,加入信號量需要全部的這些,為了省事,就不去了。
① unsem1.c。
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> void main() { printf("\nThis is unsem1 start!\n"); sleep(1); //打印完一條消息間隔會有 printf("\nThis is unsem1 end!\n"); }
② unsem2.c。
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> void main() { printf("\nThis is unsem2!\n"); }
③ 3個腳本文件。
### 腳本run.sh #!/bin/bash ./run1.sh&./run2.sh ### 腳本文件——run1.sh #!/bin/bash ./unsem1 ### 腳本文件——run2.sh #!/bin/bash ./unsem2
即腳本run.sh運行run1.sh和run2.sh,&可以進行程序的并行運行。
腳本run1.sh運行unsem1.c編譯處理的unsem1。
腳本run2.sh運行unsem2.c編譯處理的unsem2。
運行結果如下:
因為是并行運行,所以兩個程序不一定誰先運行,當unsem2先運行不影響unsem1,但當unsem1先運行時,unsem2的打印會插入到unsem1的兩個打印中間。
程序中用sleep就是為了給插入的機會。
3)加入信號量的情況
下面的文件與上面的文件放到了不同的文件夾下,所以腳本名稱是一樣的并不影響。
① sem1.c。
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/types.h> #include <sys/sem.h> #include <stdio.h> #define KEY 1234 union semun { int val; // 信號量的值 struct semid_ds *buf; unsigned short *arrry; }; void main() { key_t key; int semid; struct sembuf sop; int ret; // 創建鍵值 // key = ftok("./",1); //在當前目錄可以創建出多個鍵值,此方法沒用到 //創建信號量 semid = semget((key_t)KEY, 1, 0666 | IPC_CREAT); // 利用鍵值創建一個信號量 union semun sem_union; // 定義給信號量賦值的結構并賦值 sem_union.val = 1; ret = semctl(semid,0,SETVAL,sem_union); // 信號量的值設置為1 // ret = semctl(semid,0,GETVAL); // 獲得信號量的值,想要感受一下semctl可以放開這兩個注釋 // printf("ret value is %d\n",ret); // 1 獲取信號量 sop.sem_num = 0;//操作第一個信號量,編號為0 sop.sem_op = -1;//-1為獲取信號量 semop(semid,&sop,1);//由于定義的是變量,參數是指針所以取其地址 // 2 打印起始消息 printf("\nThis is sem1 start!\n"); // 3 間隔一會 sleep(1); // 4 打印結束消息 printf("\nThis is sem1 end!\n"); // 5 釋放信號量 sop.sem_num = 0;//操作第一個信號量,編號為0 sop.sem_op = 1;//加1為釋放信號量 semop(semid,&sop,1);//由于定義的是變量,參數是指針所以取其地址 }
② sem2.c。
#include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/types.h> #include <sys/sem.h> #include <stdio.h> #define KEY 1234 void main() { key_t key; int semid; struct sembuf sop; int ret; // 打開與sem1相同的信號量 semid = semget((key_t)KEY, 1, 0666 | IPC_CREAT); // 如果已經有這個信號量了,就不會創建,就直接打開了 ret = semctl(semid,0,GETVAL); // 獲得信號量的值 // printf("ret value is %d\n",ret); //獲取信號量 sop.sem_num = 0; // 操作第一個信號量,編號為0 sop.sem_op = -1; // -1為獲取信號量 semop(semid,&sop,1); // 由于定義的是變量,參數是指針所以取其地址 // 打印sem2的消息 printf("\nThis is sem2!\n"); //釋放信號量 sop.sem_num = 0; // 操作第一個信號量,編號為0 sop.sem_op = 1; // 加1為釋放信號量 semop(semid,&sop,1); // 由于定義的是變量,參數是指針所以取其地址 }
③ 3個腳本文件。
### 腳本run.sh #!/bin/bash ./run1.sh&./run2.sh ### 腳本文件——run1.sh #!/bin/bash ./sem1 ### 腳本文件——run2.sh #!/bin/bash ./sem2
運行結果如下:
可以看到不管是sem1先運行還是sem2先運行,sem1的兩個打印都不會被打斷的。
提示:前面學了文件的操作,這里將終端打印作為共享的資源了,你也可以用操作同一個文件的方式去驗證信號量的互斥性哈,去試試吧。
以上是“并行Shell腳本如何驗證Linux的互斥信號量”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。