Linux进程线程
1.進程
進程的引入是因為為了滿足多用戶多任務的操作的需要,對于每個任務需要分別分配一個進程進行控制。對于每個進程很顯然要標識它所擁有的資源。所以這里就引入了PCB(process control block)這個概念,對于每個PCB會有保存的各個資源變量。當你有了PCB的概念后,緊接著就是面臨三個問題就是。
1.如何創建一個進程
2. 在新建的一個進程里如何執行自己的程序
3. 創建的函數如何回收資源
這樣就引出了三個函數,fork(),execve()以及wait()函數。fork()函數是創建新進程的函數,通過一次調用兩次返回,來實現對父進程以及子進程的判斷。execve是在新創建的進程中如何load用戶想執行程序的函數。execve函數分為以下幾個函數。
1 #include <unistd.h> 2 3 int execl(const char *path, const char *arg, ...); 4 int execlp(const char *file, const char *arg, ...); 5 int execle(const char *path, const char *arg, ..., char *const envp[]); 6 int execv(const char *path, char *const argv[]); 7 int execvp(const char *file, char *const argv[]); 8 int execve(const char *path, char *const argv[], char *const envp[]);其中函數中如果缺少字母p(path) l(list) e(enviroment)則在參數中必須給出。其中execve是系統調用,其它的函數實際上還是調用它來完成功能。?
wait()函數是清理子進程的函數。如果一個進程結束了,父進程沒有調用wait()對其清理的話,那么這個進程叫做僵尸進程。而如果父進程結束了,而子進程未結束,那么這個進程的父進程改為init進程,init進程會自動清理子進程。處理僵尸進程的一個方法是利用信號來處理,因為子進程結束時會給父進程發送SIGCHILD信號,這時父進程把該信號的默認處理函數改為清理函數即可。
1 #include <sys/types.h> 2 #include <sys/wait.h> 3 4 pid_t wait(int *status); 5 pid_t waitpid(pid_t pid, int *status, int options);對于wait以及waitpid主要有兩個方面的區別
1. waitpid可以通過pid指定要清理的進程
2.其中OPTIONS指定WNOHANG可以使得waitpid不阻塞
另一個話題就是進程間的通信問題。
linux進程間的通信方法總結如下
- 通過fork函數把打開文件的描述符傳遞給子進程
- 通過wait得到子進程的終結信息
- 通過加鎖的方式,實現幾個進行共享讀寫某個文件
- 進行間通過信號通信,SIGUSR1和SIGUSR2實現用戶定義功能
- 利用pipe進行通信
- FIFO文件進行通信
- mmap,幾個進程映射到同一內存區(其中有個MAP_SHARED參數)
- SYS IPC 消息隊列,信號量(很少用)
- UNIX Domain Socket,常用
其中利用pipe函數是在內核中開辟一個緩沖區進行數據的傳送,但是如果通信的進程間沒有從公共的父進程哪里繼承文件描述符,那么要考慮使用FIFO/Socket文件進行通信,因為文件的位置是一定的,FIFO以及Socket其實不是實際存在的文件,只是用來表示內核通道的文件。
2.線程
因為進程在創建以及切換的過程中消耗的資源很大,所以就引入了線程的手段。線程其實也被稱作輕量集的進程。所以這里我們也可以利用學習進程的三個方面的問題來學習線程。
1.如何創建線程
2.如何在線程中加載要運行的函數。
3.如何回收/結束創建的線程
這里線程的創建以及加載運行所要的函數都是通過pthread_create函數來實現的。
1 #include <pthread.h> 2 3 int pthread_create(pthread_t *restrict thread, 4 const pthread_attr_t *restrict attr, 5 void *(*start_routine)(void*), void *restrict arg);其中thread是線程的pid,start_routine是線程要執行的函數指針, arg是其參數。attr則是指的線程的屬性。
結束某個線程而又不結束整個進程,可以有三個方法。
1. 從線程函數return,?
2. pthread_cancel終止同一個進程的另一個線程
3. pthread_exit終止自己
與waitpid一樣我們有時也需要獲取結束線程是否成功,這樣就引入了pthread_join()函數
1 #include <pthread.h> 2 3 int pthread_join(pthread_t thread, void **value_ptr);其主要作用是掛起等待線程的結束,并通過vaule_ptr返回其值。
由于線程中很多資源都是進程中共享的,當頻繁的對進程進行讀寫操作的時候,很容易產生訪問共享數據沖突的情形,所以需要引入鎖來解決這個問題。
1 #include <pthread.h> 2 3 int pthread_mutex_destroy(pthread_mutex_t *mutex); 4 int pthread_mutex_init(pthread_mutex_t *restrict mutex, 5 const pthread_mutexattr_t *restrict attr); 6 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 7 8 int pthread_mutex_lock(pthread_mutex_t *mutex); 9 int pthread_mutex_trylock(pthread_mutex_t *mutex); 10 int pthread_mutex_unlock(pthread_mutex_t *mutex);其中lock以及trylock的區別是一個會阻塞,一個不會阻塞。鎖所帶來的一個問題就是死鎖問題,死鎖就是多個線程加鎖與解鎖的順序不對導致其全部阻塞。這里為了防止死鎖。首先要盡量避免多次同時獲取多個鎖。實在無法避免則所有的線程按照順序獲取與釋放,如獲取鎖1,鎖2,鎖3,釋放鎖1,鎖2,鎖3.如果這個都無法保證那么就使用trylock來代替lock。
另外線程間同步機制還有其它兩種方式分別是條件變量以及信號量。
條件變量的同步主要是為了滿足這樣的一個條件,那就是當線程A阻塞時,需要線程B在某個時間喚醒它。也就是說通過線程B給其發信號。而信號量則主要是可是實現多個線程可以同時進行的鎖。互斥鎖可以看作其一種特殊的情形。信號量也可以使用在進程間同步中。
線程間通信方式如下
- 鎖機制
- 信號量機制
- 信號機制?
- 全局變量
- 參數傳遞
3. 線程與進程的比較
- 地址空間:進程內的一個執行單元;進程至少有一個線程;它們共享進程的地址空間;而進程有自己獨立的地址空間;
- 資源擁有:進程是資源分配和擁有的單位,同一個進程內的線程共享進程的資源
- 線程是處理器調度的基本單位,但進程不是.
- 二者均可并發執行.
轉載于:https://www.cnblogs.com/qtalker/p/4582059.html
總結
- 上一篇: git概念篇(remote,base,l
- 下一篇: KindEditor编辑器在ASP.NE