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