什么是進程
1、進程和線程的區別
進程是指正在運行的程序,它擁有獨立的內存空間和系統資源,不同進程之間的數據不共享。進程是資源分配的基本單位。
線程是進程內的執行單元,它與同一進程內的其他線程共享進程的內存空間和系統資源。線程是調度的基本單位。
2、進程的創建和銷毀
在Linux中啟動一個進程有多種方法:
(1)通過system函數啟動進程。(使用簡單,效率較低)
#include < stdlib.h >
/**
* @brief 執行系統命令調用命令處理器來執行命令
*
* Detailed function description
*
* @param[in] command: 包含被請求變量名稱的 C 字符串
*
* @return 如果發生錯誤,則返回值為 -1,否則返回命令的狀態。
*/
int system(const char *command);
例子:通過system函數啟動一個進程,列出當前目錄下的文件及文件夾。
#include < stdio.h >
#include < stdlib.h >
int main(void)
{
system("ls");
printf("ls end\\n");
return 0;
}
(2)通過fork函數啟動進程。(用于啟動子進程)
#include < sys/types.h >
#include < unistd.h >
/**
* @brief fork系統調用用于創建一個子進程
*
* Detailed function description
*
* @param[in]
*
* @return 如果發生錯誤,則返回值為 -1,否則返回命令的狀態。
*/
pid_t fork(void);
例子:通過fork函數啟動子進程
#include < stdio.h >
#include < stdlib.h >
#include < unistd.h >
#include < sys/wait.h >
int main(void)
{
pid_t res = fork();
///< 子進程
if (res == 0)
{
printf("res = %d, I am child process. pid = %d\\n", res, getpid());
exit(EXIT_SUCCESS); ///< 正常退出子進程
}
///< 父進程
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); ///< 父進程阻塞等待信號到來或子進程結束
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;
}
編譯、運行:
我們使用了fork()系統調用來創建一個新進程。如果fork()返回值為0,則說明當前進程是子進程;如果返回值大于0,則說明當前進程是父進程。在父進程中,我們使用wait()系統調用來等待子進程結束。當子進程結束后,父進程會繼續執行。
(3)通過exec系列函數啟動進程。(用于啟動新進程,新進程會覆蓋舊進程)
#include < unistd.h >
/**
* @brief 啟動新進程,新進程會覆蓋舊進程
*
* Detailed function description
*
* @param[in] path: 所執行文件的路徑
* @param[in] file: 所執行文件的名稱
* @param[in] arg: 傳入的參數列表,以NULL作為結束
* @param[in] envp: 傳入的環境變量
*
* @return 如果發生錯誤,則返回值為 -1,否則返回命令的狀態。
*/
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()函數的參數列表調用了ls命令程序
#include < stdio.h >
#include < unistd.h >
int main(void)
{
execl("/bin/ls", "ls", "-la", NULL);
printf("ls end\\n");
return 0;
}
execl()函數的參數列表調用了ls命令程序,與在終端上運行”ls -la”產生的結果是一樣的。
在Linux中終止一個進程有多種方法:
- 從main函數返回。(正常終止)
- 調用exit()函數終止。(正常終止)
- 調用_exit()函數終止。(正常終止)
- 調用abort()函數終止。(異常終止)
- 由系統信號終止。(異常終止)
進程間通信方式
進程間通信是指在不同進程之間傳播或交換信息的一種機制。每個進程各自有不同的用戶地址空間,任何一個進程的全局變量在另一個進程中都看不到,所以進程之間要交換數據必須通過內核,在內核中開辟一塊緩沖區,進程A把數據從用戶空間拷到內核緩沖區,進程B再從內核緩沖區把數據讀走,內核提供的這種機制稱為進程間通信。
進程間通信的目的:
- 傳輸數據。比如進程 A 負責生成數據,進程 B 負責處理數據,數據需要從 A 進程傳輸至 B 進程。
- 共享資源。比如進程 A 與進程 B 共享某一塊內存資源。
- 模塊化。將系統功能劃分為多個進程模塊進行開發,方便開發維護。
- 加速計算。多核處理器環境,一個特定進程劃分為幾個進程并行運行。
Linux IPC(Inter-process Comminication, 進程間通信)的方式:
1、消息隊列
內核中的一個優先級隊列,多個進程通過訪問同一個隊列,進行添加結點或者獲取結點實現通信。
POSIX消息隊列頭文件:
#include < fcntl.h > /* For O_* constants */
#include < sys/stat.h > /* For mode constants */
#include < mqueue.h >
編譯鏈接需要加上
-lrt
鏈接。
消息隊列API接口:
/**
* @brief 創建消息隊列實例
*
* Detailed function description
*
* @param[in] name: 消息隊列名稱
* @param[in] oflag:根據傳入標識來創建或者打開一個已創建的消息隊列
- O_CREAT: 創建一個消息隊列
- O_EXCL: 檢查消息隊列是否存在,一般與O_CREAT一起使用
- O_CREAT|O_EXCL: 消息隊列不存在則創建,已存在返回NULL
- O_NONBLOCK: 非阻塞模式打開,消息隊列不存在返回NULL
- O_RDONLY: 只讀模式打開
- O_WRONLY: 只寫模式打開
- O_RDWR: 讀寫模式打開
* @param[in] mode:訪問權限
* @param[in] attr:消息隊列屬性地址
*
* @return 成功返回消息隊列描述符,失敗返回-1,錯誤碼存于error中
*/
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
/**
* @brief 無限阻塞方式接收消息
*
* Detailed function description
*
* @param[in] mqdes: 消息隊列描述符
* @param[in] msg_ptr:消息體緩沖區地址
* @param[in] msg_len:消息體長度,長度必須大于等于消息屬性設定的最大值
* @param[in] msg_prio:消息優先級
*
* @return 成功返回消息長度,失敗返回-1,錯誤碼存于error中
*/
mqd_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
/**
* @brief 指定超時時間阻塞方式接收消息
*
* Detailed function description
*
* @param[in] mqdes: 消息隊列描述符
* @param[in] msg_ptr:消息體緩沖區地址
* @param[in] msg_len:消息體長度,長度必須大于等于消息屬性設定的最大值
* @param[in] msg_prio:消息優先級
* @param[in] abs_timeout:超時時間
*
* @return 成功返回消息長度,失敗返回-1,錯誤碼存于error中
*/
mqd_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio, const struct timespec *abs_timeout);
/**
* @brief 無限阻塞方式發送消息
*
* Detailed function description
*
* @param[in] mqdes: 消息隊列描述符
* @param[in] msg_ptr:待發送消息體緩沖區地址
* @param[in] msg_len:消息體長度
* @param[in] msg_prio:消息優先級
*
* @return 成功返回0,失敗返回-1
*/
mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
/**
* @brief 指定超時時間阻塞方式發送消息
*
* Detailed function description
*
* @param[in] mqdes: 消息隊列描述符
* @param[in] msg_ptr:待發送消息體緩沖區地址
* @param[in] msg_len:消息體長度
* @param[in] msg_prio:消息優先級
* @param[in] abs_timeout:超時時間
*
* @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 關閉消息隊列
*
* Detailed function description
*
* @param[in] mqdes: 消息隊列描述符
*
* @return 成功返回0,失敗返回-1
*/
mqd_t mq_close(mqd_t mqdes);
/**
* @brief 分離消息隊列
*
* Detailed function description
*
* @param[in] name: 消息隊列名稱
*
* @return 成功返回0,失敗返回-1
*/
mqd_t mq_unlink(const char *name);