進程是一個實體。每一個進程都有他自己的內存地址段(heap,stack等等)
進程是執行中的程序。
程序是一個沒有生命的實體,只有處理器賦予程序生命時,它才能成為一個活動的實體。
進程是操作系統中最基本、重要的概念。
線程,又是被稱為輕量級進程(Lightweight Process LWP),是程序執行的最小單元。
每一個程序都至少有一個線程,若程序只有一個線程,那么就是程序本身。
單線程的進程可以簡單的認為只有一個線程的進程。
一個進程在同一時間只做一件事,有了多線程后一個進程同一時間可以做多件事。
每個線程可以處理不同的事務。
無論系統有幾個CPU,即使進程運行在單CPU上,多線程也可以是進程並發處理多個事務。
一個線程阻塞不會影響到另一個線程。
多線程的進程可以盡可能的利用系統CPU資源。
但也不是線程越多越好,線程越好,CPU分配給每個線程的時間片就越少。
線程包含了表示進程內執行環境必須的信息,包括標識線程的線程ID,一組寄存器值,棧,調度優先級和策略,信號屏蔽字,errno變量以及線程私有數據,
對於內存,堆內存和代碼區一般屬於一個進程的,但是棧卻是屬於一個線程的,每個線程都擁有一個獨立的棧。 errno也是屬於單個線程的,每個線程中的errno是獨立的。 進程內所有的信息對於線程都是共享的,包括執行代碼,全局變量,和堆內存,棧以及文件描述符。 線程標識 --就像每個進程有個進程ID一樣,線程也有自己的ID。 --進程ID用pid_t來表示,他是一個unsigned int. --線程可以通過pthread_t表示,pthread_t不能把它當整數處理。 --線程可以通過pthread_self()函數獲得自身的線程ID
線程創建 --在進程中只有一個控制線程 --程序開始運行的時候每個進程只有一個線程,它是以單線程方式啟動的,在創建多個線程以前,進程的行為與傳統的進程沒有區別 --gcc在鏈接的時候需要增加-lpthread選項(pthread是共享庫文件)。 --創建一個線程調用pthread_create函數。 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 如果pthread_create成功返回,有thread指向的內存單元被設置為新創建線程的線程ID。 attr參數用於定制各種不同的線程屬性。 新創建的線程從start_routine函數地址開始執行,該函數只有一個void *參數,
如果需要向start_routine函數傳遞多個參數,就需要把這些參數放到一個結構中,然后把這個結構的地址作為void *傳入。 線程創建的時候不能保證哪個先運行。 pthread_create函數成功返回0,失敗返回非0,並且更新errno。 --注意:每個線程都擁有一份errno副本,不同的線程擁有不同的errno
//線程間的棧數據交互盲點 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <pthread.h> void * func(void *arg) { int num=*(int *)arg; /* 此時程序會報錯,無法獲取num的值 這是因為num在線程的棧內存中,arg指針本來是threadcreate()函數中a和b的指針, 但是a,b是個臨時變量,在控制線程的棧內存中,當執行完threadcreate()函數之后,變量a和b就會被系統釋放 此時我們在另外一個線程中取a的值就變得不可預期,因為此時a有可能已經被釋放了, 解決方案:可以在進程的堆內存上創建變量a和b,這樣在另一個線程中釋放,就沒有問題了 */ printf("num is %d\n",num); return NULL; } void threadcreate() { pthread_t thr1,thr2; int a=1,b=2; if(pthread_create(&thr1,NULL,func,&a)!=0) { printf("create thread failed!\n"); return; } if(pthread_create(&thr2,NULL,func,&b)!=0) { printf("create thread failed!\n"); return; } } int main(int arg,char *args[]) { threadcreate(); sleep(2); return 0; }
.SUFFIXES:.c .o CC=gcc SRCS=tec01.c OBJS=$(SRCS:.c=.o) EXEC=tec start:$(OBJS) $(CC) -lpthread -o $(EXEC) $(OBJS) @echo "^_^-----OK------^_^" .c.o: $(CC) -Wall -g -o $@ -c $< clean: rm -f $(OBJS) rm -f $(EXEC)
線程終止 --任一線程調用了exit函數,整個進程就會終止。 --如果信號默認動作是終止進程,那么信號發送到該進程,整個進程也會被終止。 單個線程通過以下三種方式退出 --線程只是從啟動函數中返回,返回值是線程的退出碼 --線程可以被同一進程中的其他線程取消。 --線程調用pthread_exit。 void pthread_exit(void * arg); arg是個無類型指針,該指針會被其他線程調用pthread_join捕捉。 在線程的子函數中調用pthread_exit()函數,線程也會退出,這點跟exit()函數相同。 線程之間是異步的,無法確定哪個線程先執行。 進程內的信號捕捉一般在控制線程內進行 pthread_create()函數的第四個參數對應回調函數的參數