進程是一個實體。每一個進程都有他自己的內存地址段(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()函數的第四個參數對應回調函數的參數