什么是進(jìn)程
1、進(jìn)程和線程的區(qū)別
進(jìn)程是指正在運(yùn)行的程序,它擁有獨(dú)立的內(nèi)存空間和系統(tǒng)資源,不同進(jìn)程之間的數(shù)據(jù)不共享。進(jìn)程是資源分配的基本單位。
線程是進(jìn)程內(nèi)的執(zhí)行單元,它與同一進(jìn)程內(nèi)的其他線程共享進(jìn)程的內(nèi)存空間和系統(tǒng)資源。線程是調(diào)度的基本單位。
2、進(jìn)程的創(chuàng)建和銷毀
在Linux中啟動(dòng)一個(gè)進(jìn)程有多種方法:
(1)通過system函數(shù)啟動(dòng)進(jìn)程。(使用簡(jiǎn)單,效率較低)
?
#include? /** ?*?@brief?執(zhí)行系統(tǒng)命令調(diào)用命令處理器來執(zhí)行命令 ?* ?*?Detailed?function?description ?* ?*?@param[in]?command:?包含被請(qǐng)求變量名稱的?C?字符串 ?* ?*?@return?如果發(fā)生錯(cuò)誤,則返回值為?-1,否則返回命令的狀態(tài)。 ?*/ int?system(const?char?*command);
?
例子:通過system函數(shù)啟動(dòng)一個(gè)進(jìn)程,列出當(dāng)前目錄下的文件及文件夾。
?
#include?
#include?
int?main(void)
{
????system("ls");
????printf("ls?end
");
????return?0;
}
?
(2)通過fork函數(shù)啟動(dòng)進(jìn)程。(用于啟動(dòng)子進(jìn)程)
?
#include? #include? /** ?*?@brief?fork系統(tǒng)調(diào)用用于創(chuàng)建一個(gè)子進(jìn)程 ?* ?*?Detailed?function?description ?* ?*?@param[in] ?* ?*?@return?如果發(fā)生錯(cuò)誤,則返回值為?-1,否則返回命令的狀態(tài)。 ?*/ pid_t?fork(void);
?
例子:通過fork函數(shù)啟動(dòng)子進(jìn)程
?
#include?
#include?
#include?
#include?
int?main(void)?
{
????pid_t?res?=?fork();
????///?0)?
????{
????????printf("res?=?%d,?I?am?parent?process.?pid?=?%d
",?res,?getpid());
????????int?child_status?=?0;
????????pid_t?child_pid?=?wait(&child_status);???///
?
編譯、運(yùn)行:

我們使用了fork()系統(tǒng)調(diào)用來創(chuàng)建一個(gè)新進(jìn)程。如果fork()返回值為0,則說明當(dāng)前進(jìn)程是子進(jìn)程;如果返回值大于0,則說明當(dāng)前進(jìn)程是父進(jìn)程。在父進(jìn)程中,我們使用wait()系統(tǒng)調(diào)用來等待子進(jìn)程結(jié)束。當(dāng)子進(jìn)程結(jié)束后,父進(jìn)程會(huì)繼續(xù)執(zhí)行。
(3)通過exec系列函數(shù)啟動(dòng)進(jìn)程。(用于啟動(dòng)新進(jìn)程,新進(jìn)程會(huì)覆蓋舊進(jìn)程)
?
#include?
/**
?*?@brief?啟動(dòng)新進(jìn)程,新進(jìn)程會(huì)覆蓋舊進(jìn)程
?*
?*?Detailed?function?description
?*
?*?@param[in]?path:?所執(zhí)行文件的路徑
?*?@param[in]?file:?所執(zhí)行文件的名稱
?*?@param[in]?arg:?傳入的參數(shù)列表,以NULL作為結(jié)束
?*?@param[in]?envp:?傳入的環(huán)境變量
?*
?*?@return?如果發(fā)生錯(cuò)誤,則返回值為?-1,否則返回命令的狀態(tài)。
?*/
int?execl(const?char?*path,?const?char?*arg,?...);
int?execlp(const?char?*file,?const?char?*arg,?...);
int?execle(const?char?*path,?const?char?*arg,?...,?char?*const?envp[]);
int?execv(const?char?*path,?char?*const?argv[]);
int?execvp(const?char?*file,?char?*const?argv[]);
int?execve(const?char?*path,?char?*const?argv[],?char?*const?envp[]);
?
例子:通過execl()函數(shù)的參數(shù)列表調(diào)用了ls命令程序
?
#include?
#include?
int?main(void)
{
????execl("/bin/ls",?"ls",?"-la",?NULL);
????printf("ls?end
");
????return?0;
}
?
execl()函數(shù)的參數(shù)列表調(diào)用了ls命令程序,與在終端上運(yùn)行”ls -la”產(chǎn)生的結(jié)果是一樣的。
在Linux中終止一個(gè)進(jìn)程有多種方法:
從main函數(shù)返回。(正常終止)
調(diào)用exit()函數(shù)終止。(正常終止)
調(diào)用_exit()函數(shù)終止。(正常終止)
調(diào)用abort()函數(shù)終止。(異常終止)
由系統(tǒng)信號(hào)終止。(異常終止)
進(jìn)程間通信方式
進(jìn)程間通信是指在不同進(jìn)程之間傳播或交換信息的一種機(jī)制。每個(gè)進(jìn)程各自有不同的用戶地址空間,任何一個(gè)進(jìn)程的全局變量在另一個(gè)進(jìn)程中都看不到,所以進(jìn)程之間要交換數(shù)據(jù)必須通過內(nèi)核,在內(nèi)核中開辟一塊緩沖區(qū),進(jìn)程A把數(shù)據(jù)從用戶空間拷到內(nèi)核緩沖區(qū),進(jìn)程B再從內(nèi)核緩沖區(qū)把數(shù)據(jù)讀走,內(nèi)核提供的這種機(jī)制稱為進(jìn)程間通信。
進(jìn)程間通信的目的:
傳輸數(shù)據(jù)。比如進(jìn)程 A 負(fù)責(zé)生成數(shù)據(jù),進(jìn)程 B 負(fù)責(zé)處理數(shù)據(jù),數(shù)據(jù)需要從 A 進(jìn)程傳輸至 B 進(jìn)程。
共享資源。比如進(jìn)程 A 與進(jìn)程 B 共享某一塊內(nèi)存資源。
模塊化。將系統(tǒng)功能劃分為多個(gè)進(jìn)程模塊進(jìn)行開發(fā),方便開發(fā)維護(hù)。
加速計(jì)算。多核處理器環(huán)境,一個(gè)特定進(jìn)程劃分為幾個(gè)進(jìn)程并行運(yùn)行。
Linux IPC(Inter-process Comminication, 進(jìn)程間通信)的方式:

1、消息隊(duì)列
內(nèi)核中的一個(gè)優(yōu)先級(jí)隊(duì)列,多個(gè)進(jìn)程通過訪問同一個(gè)隊(duì)列,進(jìn)行添加結(jié)點(diǎn)或者獲取結(jié)點(diǎn)實(shí)現(xiàn)通信。
POSIX消息隊(duì)列頭文件:
?
#include????????????/*?For?O_*?constants?*/
#include?????????/*?For?mode?constants?*/
#include?
?
編譯鏈接需要加上 -lrt 鏈接。
消息隊(duì)列API接口:
?
/**
?*?@brief?創(chuàng)建消息隊(duì)列實(shí)例
?*
?*?Detailed?function?description
?*
?*?@param[in]?name:?消息隊(duì)列名稱
?*?@param[in]?oflag:根據(jù)傳入標(biāo)識(shí)來創(chuàng)建或者打開一個(gè)已創(chuàng)建的消息隊(duì)列
????????????????????-?O_CREAT:?創(chuàng)建一個(gè)消息隊(duì)列
????????????????????-?O_EXCL:?檢查消息隊(duì)列是否存在,一般與O_CREAT一起使用
????????????????????-?O_CREAT|O_EXCL:?消息隊(duì)列不存在則創(chuàng)建,已存在返回NULL
????????????????????-?O_NONBLOCK:?非阻塞模式打開,消息隊(duì)列不存在返回NULL
????????????????????-?O_RDONLY:?只讀模式打開
????????????????????-?O_WRONLY:?只寫模式打開
????????????????????-?O_RDWR:?讀寫模式打開
?*?@param[in]?mode:訪問權(quán)限
?*?@param[in]?attr:消息隊(duì)列屬性地址
?*
?*?@return?成功返回消息隊(duì)列描述符,失敗返回-1,錯(cuò)誤碼存于error中
?*/
mqd_t?mq_open(const?char?*name,?int?oflag,??mode_t?mode,?struct?mq_attr?*attr);
/**
?*?@brief?無限阻塞方式接收消息
?*
?*?Detailed?function?description
?*
?*?@param[in]?mqdes:?消息隊(duì)列描述符
?*?@param[in]?msg_ptr:消息體緩沖區(qū)地址
?*?@param[in]?msg_len:消息體長(zhǎng)度,長(zhǎng)度必須大于等于消息屬性設(shè)定的最大值
?*?@param[in]?msg_prio:消息優(yōu)先級(jí)
?*
?*?@return?成功返回消息長(zhǎng)度,失敗返回-1,錯(cuò)誤碼存于error中
?*/
mqd_t?mq_receive(mqd_t?mqdes,?char?*msg_ptr,?size_t?msg_len,?unsigned?*msg_prio);
/**
?*?@brief?指定超時(shí)時(shí)間阻塞方式接收消息
?*
?*?Detailed?function?description
?*
?*?@param[in]?mqdes:?消息隊(duì)列描述符
?*?@param[in]?msg_ptr:消息體緩沖區(qū)地址
?*?@param[in]?msg_len:消息體長(zhǎng)度,長(zhǎng)度必須大于等于消息屬性設(shè)定的最大值
?*?@param[in]?msg_prio:消息優(yōu)先級(jí)
?*?@param[in]?abs_timeout:超時(shí)時(shí)間
?*
?*?@return?成功返回消息長(zhǎng)度,失敗返回-1,錯(cuò)誤碼存于error中
?*/
mqd_t?mq_timedreceive(mqd_t?mqdes,?char?*msg_ptr,?size_t?msg_len,?unsigned?*msg_prio,?const?struct?timespec?*abs_timeout);
/**
?*?@brief?無限阻塞方式發(fā)送消息
?*
?*?Detailed?function?description
?*
?*?@param[in]?mqdes:?消息隊(duì)列描述符
?*?@param[in]?msg_ptr:待發(fā)送消息體緩沖區(qū)地址
?*?@param[in]?msg_len:消息體長(zhǎng)度
?*?@param[in]?msg_prio:消息優(yōu)先級(jí)
?*
?*?@return?成功返回0,失敗返回-1
?*/
mqd_t?mq_send(mqd_t?mqdes,?const?char?*msg_ptr,?size_t?msg_len,?unsigned?msg_prio);
/**
?*?@brief?指定超時(shí)時(shí)間阻塞方式發(fā)送消息
?*
?*?Detailed?function?description
?*
?*?@param[in]?mqdes:?消息隊(duì)列描述符
?*?@param[in]?msg_ptr:待發(fā)送消息體緩沖區(qū)地址
?*?@param[in]?msg_len:消息體長(zhǎng)度
?*?@param[in]?msg_prio:消息優(yōu)先級(jí)
?*?@param[in]?abs_timeout:超時(shí)時(shí)間
?*
?*?@return?成功返回0,失敗返回-1
?*/
mqd_t?mq_timedsend(mqd_t?mqdes,?const?char?*msg_ptr,?size_t?msg_len,?unsigned?msg_prio,?const?struct?timespec?*abs_timeout);
/**
?*?@brief?關(guān)閉消息隊(duì)列
?*
?*?Detailed?function?description
?*
?*?@param[in]?mqdes:?消息隊(duì)列描述符
?*
?*?@return?成功返回0,失敗返回-1
?*/
mqd_t?mq_close(mqd_t?mqdes);
/**
?*?@brief?分離消息隊(duì)列
?*
?*?Detailed?function?description
?*
?*?@param[in]?name:?消息隊(duì)列名稱
?*
?*?@return?成功返回0,失敗返回-1
?*/
mqd_t?mq_unlink(const?char?*name);
?
消息隊(duì)列基本API接口使用例子:發(fā)送進(jìn)程給接收進(jìn)程發(fā)送測(cè)試數(shù)據(jù)。
send.c:
?
#include?
#include?
#include?
#include?
#include????????????/*?For?O_*?constants?*/
#include?????????/*?For?mode?constants?*/
#include?
#define?MQ_MSG_MAX_SIZE????512??///
?
recv.c:
?
#include?
#include?
#include?
#include?
#include????????????/*?For?O_*?constants?*/
#include?????????/*?For?mode?constants?*/
#include?
#define?MQ_MSG_MAX_SIZE????512??///
?
編譯、運(yùn)行:
?
gcc?send.c?-o?send_process?-lrt
gcc?recv.c?-o?recv_process?-lrt

?
2、共享內(nèi)存
消息隊(duì)列的讀取和寫入的過程,會(huì)有發(fā)生用戶態(tài)與內(nèi)核態(tài)之間的消息拷貝過程。而共享內(nèi)存的方式則沒有這個(gè)拷貝過程,進(jìn)程間通信速度較快。
在物理內(nèi)存上開辟一塊內(nèi)存空間,多個(gè)進(jìn)程可以將同一塊物理內(nèi)存空間映射到自己的虛擬地址空間,通過自己的虛擬地址直接訪問這塊空間,通過這種方式實(shí)現(xiàn)數(shù)據(jù)共享。

POSIX共享內(nèi)存頭文件:
?
#include?
#include?
#include?
?
共享內(nèi)存API接口:
?
/**
?*?@brief?創(chuàng)建共享內(nèi)存實(shí)例
?*
?*?Detailed?function?description
?*
?*?@param[in]?name:?要打開或創(chuàng)建的共享內(nèi)存文件名
?*?@param[in]?oflag:打開的文件操作屬性
????????????????????-?O_CREAT:?創(chuàng)建一個(gè)共享內(nèi)存文件
????????????????????-?O_EXCL:?檢查共享內(nèi)存是否存在,一般與O_CREAT一起使用
????????????????????-?O_CREAT|O_EXCL:?共享內(nèi)存不存在則創(chuàng)建,已存在返回NULL
????????????????????-?O_NONBLOCK:?非阻塞模式打開,共享內(nèi)存不存在返回NULL
????????????????????-?O_RDONLY:?只讀模式打開
????????????????????-?O_WRONLY:?只寫模式打開
????????????????????-?O_RDWR:?讀寫模式打開
?*?@param[in]?mode:文件共享模式,例如?0777
?*
?*?@return?成功返回共享內(nèi)存描述符,失敗返回-1,錯(cuò)誤碼存于error中
?*/
int?shm_open(const?char?*name,?int?oflag,?mode_t?mode);
/**
?*?@brief?刪除共享內(nèi)存
?*
?*?Detailed?function?description
?*
?*?@param[in]?name:?創(chuàng)建的共享內(nèi)存文件名
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?shm_unlink(const?char?*name);
/**
?*?@brief?將打開的文件映射到內(nèi)存
?*
?*?Detailed?function?description
?*
?*?@param[in]?addr:?要將文件映射到的內(nèi)存地址,一般應(yīng)該傳遞NULL來由Linux內(nèi)核指定
?*?@param[in]?length:?要映射的文件數(shù)據(jù)長(zhǎng)度
?*?@param[in]?prot:?映射的內(nèi)存區(qū)域的操作權(quán)限(保護(hù)屬性),包括PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE
?*?@param[in]?flags:?標(biāo)志位參數(shù),包括:MAP_SHARED、MAP_PRIVATE與MAP_ANONYMOUS。
?*?@param[in]?fd:??用來建立映射區(qū)的文件描述符,用?shm_open打開或者open打開的文件
?*?@param[in]?offset:?映射文件相對(duì)于文件頭的偏移位置,應(yīng)該按4096字節(jié)對(duì)齊
?*
?*?@return?成功返回0,失敗返回-1
?*/
void?*mmap(void?*addr,?size_t?length,?int?prot,?int?flags,?int?fd,?off_t?offset);
?
/**
?*?@brief?取消內(nèi)存映射
?*
?*?Detailed?function?description
?*
?*?@param[in]?addr:?由mmap成功返回的地址
?*?@param[in]?length:?要取消的內(nèi)存長(zhǎng)度
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?munmap(void?*addr,?size_t?length);
/**
?*?@brief?將參數(shù)fd指定的文件大小改為參數(shù)length指定的大小
?*
?*?Detailed?function?description
?*
?*?@param[in]?fd:?已打開的文件描述符,以寫入模式打開的文件
?*?@param[in]?length:?要設(shè)置的長(zhǎng)度
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?ftruncate(int?fd,off_t?length);
/**
?*?@brief?獲取文件相關(guān)的信息,將獲取到的信息放入到statbuf結(jié)構(gòu)體中
?*
?*?Detailed?function?description
?*
?*?@param[in]?fd:?已打開的文件描述符
?*?@param[out]?statbuf:?文件的信息
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?fstat(int?fd,?struct?stat?*statbuf);
?
共享內(nèi)存基本API接口使用例子:發(fā)送進(jìn)程給接收進(jìn)程發(fā)送測(cè)試數(shù)據(jù)。
send.c:
?
#include?
#include?
#include?
#include?
#include????????????/*?For?O_*?constants?*/
#include?????????/*?For?mode?constants?*/
#include?
#define?SHM_NAME?"/shm"
int?main(void)
{
????int?ret?=?0;
????///
?
recv.c:
?
#include?
#include?
#include?
#include?
#include????????????/*?For?O_*?constants?*/
#include?????????/*?For?mode?constants?*/
#include?
#define?SHM_NAME?"/shm"
int?main(void)
{
????///
?
編譯、運(yùn)行:
?
gcc?send.c?-o?send_process?-lrt
gcc?recv.c?-o?recv_process?-lrt

?
對(duì)具有多個(gè)處理核系統(tǒng)消息傳遞的性能要優(yōu)于共享內(nèi)存。共享內(nèi)存會(huì)有高速緩存一致性問題,這是由共享數(shù)據(jù)在多個(gè)高速緩存之間遷移而引起的。隨著系統(tǒng)的處理核的數(shù)量的日益增加,可能導(dǎo)致消息傳遞作為 IPC 的首選機(jī)制。
3、socket
UNIX域套接字與傳統(tǒng)基于TCP/IP協(xié)議棧的socket不同,unix domain socket以文件系統(tǒng)作為地址空間,不需經(jīng)過TCP/IP的頭部封裝、報(bào)文ack確認(rèn)、路由選擇、數(shù)據(jù)校驗(yàn)與重傳過程,因此傳輸速率上也不會(huì)受網(wǎng)卡帶寬的限制。
unix domain socket在進(jìn)程間通信同樣是基于“客戶端—服務(wù)器”(C-S)模式。
UNIX域套接字基本API接口使用例子:基于UNIX域套接字客戶端進(jìn)程向服務(wù)端進(jìn)程發(fā)送測(cè)試數(shù)據(jù)。
server.c:
?
#include?
#include?
#include?
#include?
#include????????????/*?For?O_*?constants?*/
#include?????????/*?For?mode?constants?*/
#include?
#include?
#include?
#include?
#define?SERVER_PATH?"/tmp/server"?
int?main(void)
{
?///
?
client.c:
?
#include?
#include?
#include?
#include?
#include????????????/*?For?O_*?constants?*/
#include?????????/*?For?mode?constants?*/
#include?
#include?
#include?
#include?
#define?SERVER_PATH?"/tmp/server"
#define?CLIENT_PATH?"/tmp/client"
int?main(void)
{
?///
?
編譯、運(yùn)行:
?
gcc?server.c?-o?server_process
gcc?client.c?-o?client_process

?
類socket的其它進(jìn)程間通信方式:
實(shí)用 | nanomsg通信庫的簡(jiǎn)單使用分享
mqtt應(yīng)用于進(jìn)程間通信
4、管道
在內(nèi)核中開辟一塊緩沖區(qū);若多個(gè)進(jìn)程拿到同一個(gè)管道(緩沖區(qū))的操作句柄,就可以訪問同一個(gè)緩沖區(qū),就可以進(jìn)行通信。涉及到兩次用戶態(tài)與內(nèi)核態(tài)之間的數(shù)據(jù)拷貝。
(1)匿名管道
內(nèi)核中的緩沖區(qū)是沒有具體的標(biāo)識(shí)符的,匿名管道只能用于具有親緣關(guān)系的進(jìn)程間通信。

調(diào)用pipe接口可以創(chuàng)建一個(gè)匿名管道,并返回了兩個(gè)描述符,一個(gè)是管道的讀取端描述符 fd[0],另一個(gè)是管道的寫入端描述符 fd[1]。
管道是一個(gè)半雙工通信(可以選擇方向的單向傳輸)
匿名管道基本API接口使用例子:父進(jìn)程通過管道發(fā)送測(cè)試數(shù)據(jù)給子進(jìn)程。
?
#include?
#include?
#include?
#include?
int?main()
{
????///?0)
???{
??///
?
編譯、運(yùn)行:

如果需要雙向通信,則應(yīng)該創(chuàng)建兩個(gè)管道。
(2)命名管道
命名管道也是內(nèi)核中的一塊緩沖區(qū),并且這個(gè)緩沖區(qū)具有標(biāo)識(shí)符;這個(gè)標(biāo)識(shí)符是一個(gè)可見于文件系統(tǒng)的管道文件,能夠被其他進(jìn)程找到并打開管道文件,則可以獲取管道的操作句柄,所以該命名管道可用于同一主機(jī)上的任意進(jìn)程間通信。
創(chuàng)建命名管道的接口:
?
int?mkfifo(const?char?*pathname,?mode_t?mode);
?
命名管道基本API接口使用例子:一個(gè)進(jìn)程往管道中寫入測(cè)試數(shù)據(jù),另一個(gè)進(jìn)程從管道中讀取數(shù)據(jù)。
fifo_wr.c:
?
#include?
#include?
#include?
#include?
#include?
#include?
#include?
#define?FIFO_PATH??"./fifo_file"
typedef?struct?_msg_data
{
????char?buf[128];
????int?cnt;
}msg_data_t;
void?send_data(int?fd)
{
????static?int?cnt?=?0;
????msg_data_t?send_data?=?{0};
????cnt++;
????strcpy(send_data.buf,?"hello");
????send_data.cnt?=?cnt;
????write(fd,?&send_data,?sizeof(send_data));
????printf("send?msg?=?%s,?cnt?=?%d
",?send_data.buf,?send_data.cnt);
}
int?main(void)
{
????///
?
fifo_rd.c:
?
#include?
#include?
#include?
#include?
#include?
#include?
#include?
#define?FIFO_PATH??"./fifo_file"
typedef?struct?_msg_data
{
????char?buf[128];
????int?cnt;
}msg_data_t;
int?main(void)
{
????umask(0);
????///
?
編譯、運(yùn)行:
?
gcc?fifo_wr.c?-o?fifo_wr
gcc?fifo_rd.c?-o?fifo_rd

?
5、信號(hào)量
信號(hào)量(Seamphore)是進(jìn)程和線程間同步的一種機(jī)制。
信號(hào)量本質(zhì)是一個(gè)非負(fù)的整型變量。增加一個(gè)可用資源執(zhí)行加一,也稱為V操作;獲取一個(gè)資源資源后執(zhí)行減一,也稱為P操作。
信號(hào)量根據(jù)信號(hào)值不同可分為兩類:
二值信號(hào)量,信號(hào)量值只有0和1,初始值為1,1表示資源可用,0表示資源不可用;二值信號(hào)量與互斥鎖類似。
計(jì)數(shù)信號(hào)量, 信號(hào)量的值在0到一個(gè)大于1的限制值之間,信號(hào)值表示可用的資源的數(shù)目。
信號(hào)量根據(jù)作用對(duì)象不同可分為兩類:
有名信號(hào)量,信號(hào)值保存在文件中,用于進(jìn)程間同步
無名信號(hào)量,又稱為基于內(nèi)存信號(hào)量,信號(hào)值保存在內(nèi)存中,用于線程間同步
POSIX信號(hào)量頭文件:
?
#include?
?
編譯鏈接需要加-lpthread參數(shù)。
信號(hào)量API接口:
?
/**
?*?@brief?創(chuàng)建信號(hào)量
?*
?*?Detailed?function?description
?*
?*?@param[in]?name:?信號(hào)量名稱
?*?@param[in]?mode:?訪問權(quán)限
?*?@param[in]?value:?信號(hào)量初始值
?*
?*?@return?成功時(shí)返回指向信號(hào)量的指針,出錯(cuò)時(shí)為SEM_FAILED
?*/
sem_t?*sem_open(const?char?*name,int?oflag,?mode_t?mode,?unsigned?int?value);
/**
?*?@brief?初始化信號(hào)量
?*
?*?Detailed?function?description
?*
?*?@param[in]?sem:?信號(hào)量實(shí)例地址
?*?@param[in]?pshared:?信號(hào)量作用域,分為進(jìn)程內(nèi)作用域PTHREAD_PROCESS_PRIVATE和跨進(jìn)程作用域PTHREAD_PROCESS_SHARED
?*?@param[in]?value:?信號(hào)量初始值
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?sem_init(sem_t?*sem,?int?pshared,?unsigned?int?value);
/**
?*?@brief?獲取信號(hào)量
?*
?*?Detailed?function?description
?*
?*?@param[in]?sem:?信號(hào)量實(shí)例地址
?*?@param[out]?sval:?保存返回信號(hào)值地址
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?sem_getvalue(sem_t?*sem,?int?*sval);
/**
?*?@brief?阻塞方式等待信號(hào)量
?*
?*?Detailed?function?description
?*
?*?@param[in]?sem:?信號(hào)量實(shí)例地址
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?sem_wait(sem_t?*sem);
/**
?*?@brief?指定超時(shí)時(shí)間阻塞方式等待信號(hào)量
?*
?*?Detailed?function?description
?*
?*?@param[in]?sem:?信號(hào)量實(shí)例地址
?*?@param[in]?sem:?超時(shí)時(shí)間,單位為時(shí)鐘節(jié)拍
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?sem_timedwait(sem_t?*sem,?const?struct?timespec?*abs_timeout);
/**
?*?@brief?非阻塞方式等待信號(hào)量
?*
?*?Detailed?function?description
?*
?*?@param[in]?sem:?信號(hào)量實(shí)例地址
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?sem_trywait(sem_t?*sem);
/**
?*?@brief?產(chǎn)生信號(hào)量
?*
?*?Detailed?function?description
?*
?*?@param[in]?sem:?信號(hào)量實(shí)例地址
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?sem_post(sem_t?*sem);
/**
?*?@brief?銷毀信號(hào)量
?*
?*?Detailed?function?description
?*
?*?@param[in]?sem:?信號(hào)量實(shí)例地址
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?sem_destroy(sem_t?*sem);
/**
?*?@brief?關(guān)閉信號(hào)量
?*
?*?Detailed?function?description
?*
?*?@param[in]?sem:?信號(hào)量實(shí)例地址
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?sem_close(sem_t?*sem);
/**
?*?@brief?分離信號(hào)量
?*
?*?Detailed?function?description
?*
?*?@param[in]?name:?信號(hào)量名稱
?*
?*?@return?成功返回0,失敗返回-1
?*/
int?sem_unlink(const?char?*name);
?
信號(hào)量基本API接口使用例子:父子進(jìn)程間通信
?
#include?
#include?
#include?
#include?
#include?
#define?SEM_NAME?"sem"
int?main?(void)
{
????int?sem_val?=?0;
????///?0)
????{
????????///
?
編譯、運(yùn)行:

IPC總結(jié)
操作系統(tǒng)根據(jù)不同的場(chǎng)景提供了不同的方式,消息隊(duì)列、共享內(nèi)存、UNIX域套接字、管道、信號(hào)量。
消息隊(duì)列: 內(nèi)核中的一個(gè)優(yōu)先級(jí)隊(duì)列,多個(gè)進(jìn)程通過訪問同一個(gè)隊(duì)列,在隊(duì)列當(dāng)中添加或者獲取節(jié)點(diǎn)來實(shí)現(xiàn)進(jìn)程間通信。
共享內(nèi)存: 本質(zhì)是一塊物理內(nèi)存,多個(gè)進(jìn)程將同一塊物理內(nèi)存映射到自己的虛擬地址空間中,再通過頁表映射到物理地址達(dá)到進(jìn)程間通信,它是最快的進(jìn)程間通信方式,相較其他通信方式少了兩步數(shù)據(jù)拷貝操作。
UNIX域套接字: 與TCP/IP套接字使用方式相同,但UNIX域套接字以文件系統(tǒng)作為地址空間,不需經(jīng)過TCP/IP的頭部封裝、報(bào)文ack確認(rèn)、路由選擇、數(shù)據(jù)校驗(yàn)與重傳過程,因此傳輸速率上也不會(huì)受網(wǎng)卡帶寬的限制。
管道: 內(nèi)核中的一塊緩沖區(qū),分為匿名管道和命名管道。匿名管道只能用于具有親緣關(guān)系的進(jìn)程間;而命名管道可用于同一主機(jī)上任意進(jìn)程間通信。
信號(hào)量: 本質(zhì)是內(nèi)核中的一個(gè)計(jì)數(shù)器,主要實(shí)現(xiàn)進(jìn)程間的同步與互斥,對(duì)資源進(jìn)行計(jì)數(shù),有兩種操作,分別是在訪問資源之前進(jìn)行的p操作,還有產(chǎn)生資源之后的v操作。
審核編輯:湯梓紅
電子發(fā)燒友App













評(píng)論