什么是進(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)程。(使用簡單,效率較低)
#include < stdlib.h >
/**
* @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 < stdio.h >
#include < stdlib.h >
int main(void)
{
system("ls");
printf("ls end\\n");
return 0;
}
(2)通過fork函數(shù)啟動(dòng)進(jìn)程。(用于啟動(dòng)子進(jìn)程)
#include < sys/types.h >
#include < unistd.h >
/**
* @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 < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < sys/wait.h >
int main(void)
{
pid_t res = fork();
///< 子進(jìn)程
if (res == 0)
{
printf("res = %d, I am child process. pid = %d\\n", res, getpid());
exit(EXIT_SUCCESS); ///< 正常退出子進(jìn)程
}
///< 父進(jìn)程
else if (res > 0)
{
printf("res = %d, I am parent process. pid = %d\\n", res, getpid());
int child_status = 0;
pid_t child_pid = wait(&child_status); ///< 父進(jìn)程阻塞等待信號(hào)到來或子進(jìn)程結(jié)束
printf("Child process(pid = %d) has been terminated, child_status = %d\\n", child_pid, child_status);
}
///< 異常退出
else
{
printf("Fork failed.\\n");
exit(EXIT_FAILURE);
}
return 0;
}
編譯、運(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 < unistd.h >
/**
* @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 < stdio.h >
#include < unistd.h >
int main(void)
{
execl("/bin/ls", "ls", "-la", NULL);
printf("ls end\\n");
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 < fcntl.h > /* For O_* constants */
#include < sys/stat.h > /* For mode constants */
#include < mqueue.h >
編譯鏈接需要加上
-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:消息體長度,長度必須大于等于消息屬性設(shè)定的最大值
* @param[in] msg_prio:消息優(yōu)先級(jí)
*
* @return 成功返回消息長度,失敗返回-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:消息體長度,長度必須大于等于消息屬性設(shè)定的最大值
* @param[in] msg_prio:消息優(yōu)先級(jí)
* @param[in] abs_timeout:超時(shí)時(shí)間
*
* @return 成功返回消息長度,失敗返回-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:消息體長度
* @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:消息體長度
* @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);