1 線程不能獨立運行,要依附于進程
2 如果創建一個子線程只需要重新分配棧空間
3 多個線程可以并行運行
4 線程之間可以有共同的全局變量(全局區,任何線程都可以訪問)
5 多線程效率高
如何創建子線程(在進程中創建線程)
#include
int pthread_create(pthread_t *thread, pthread_arrt_t *attr, void *(*start_routine)(void *), void *arg);
功能:創建一個子線程
參數:
thread [出參],當程序執行此函數,此函數會傳出一個值,線程的id
attr [入參],通常為NULL, 線程的屬性,如果為NULL, 屬性默認(線程優先級,線程堆棧大小....)
start_routine 函數指針,需要傳進來一個函數名,然后會自動執行此函數,
此函數就是線程需要執行的程序
arg 此參數專門給第三個參數start_routine使用的,此參數,作為start_routine函數的參數
int process(int (*p)(int, int), int a, int b)
{
p(a, b);
}
創建一個線程實例:
#include
#include
void *fun(void *p)
{
while(1)
{
printf("thread 1 running\n");
sleep(1);
}
}
int main()
{
pthread_t id;
pthread_create(&id, NULL, fun, NULL);
printf("%lu\n", id);
while(1) //目的:讓主進程不結束
{
;
}
}
編譯時: gcc -o hello hello.c -lpthread //多線程是一個第三庫函數,所以要加-lpthread
多線程的好處:
要實現 1 接收鍵盤輸入 2 同時每隔一秒鐘打印一下家中的溫度
pthread_join(); ///函數功能:主進程如果執行到此函數,將阻塞,等待子線程結束
#include
#include
void *fun(void *p)
{
while(1)
{
printf("thread 1 running\n");
sleep(1);
}
}
int main()
{
pthread_t id;
pthread_create(&id, NULL, fun, NULL);
printf("%lu\n", id);
pthread_join(id, NULL); //阻塞,等待子線程結束, 節省cpu資源
}
線程參數
//////////////實例:傳遞字符串給線程/////////////////////
#include
#include
void *fun(void *p)
{
//char *q = (char *)p;
while(1)
{
printf("%s\n", (char *)p);
sleep(1);
}
}
int main()
{
char s[] = "hello world";
pthread_t id;
pthread_create(&id, NULL, fun, s);
printf("%lu\n", id);
pthread_join(id, NULL); //阻塞,等待子線程結束, 節省cpu資源
}
//////////////實例:傳遞整形變量給線程/////////////////////
#include
#include
void *fun(void *p)
{
int *q = (int *)p;
while(1)
{
printf("%d\n", *q);
sleep(1);
}
}
int main()
{
int a = 100;
pthread_t id;
pthread_create(&id, NULL, fun, &a);
printf("%lu\n", id);
pthread_join(id, NULL); //阻塞,等待子線程結束, 節省cpu資源
}
void *p ///無類型指針,可以定義變量,但不可以使用(*p = 100, p++, p--)
///無類型指針只能賦值給另一個帶類型的指針變量
線程的同步與互斥
同步(按照預想的順序執行)
M->Y->M->Y->M->Y
M->YYY->M->YYY......
互斥
你用,我不能用(如:網絡打印機,A 打印時, B不可以打印)
/////互斥例子
#include
#include
int a[10] = { 0 }; ///共享資源
int i;
void *fun1()
{
while(1)
{
int i;
for(i = 0; i < 10; i++)
{
a[i] = i;
}
sleep(2);
for(i = 0; i < 10; i++)
{
printf("a[%d] is %d\n", i, a[i]);
}
}
}
void *fun2()
{
while(1)
{
sleep(1);
for(i = 0; i < 10; i++)
{
a[i] = 1;
}
}
}
int main()
{
pthread_t id1, id2;
pthread_create(&id1, NULL, fun1, NULL);
pthread_create(&id2, NULL, fun2, NULL);
pthread_join(id1, NULL);
}
//////線程同步(mutex)
A 使用共享資源,加鎖,如果這時B也使用共享資源,
B也加鎖,但是鎖已經被A占用,B只能等,一旦A解鎖,B運行,加鎖,使用共享資源
//////互斥鎖,用來解決共享資源同步的問題,(互斥鎖初始化)
pthread_mutex_t 互斥鎖類型結構體
1 創建互斥鎖(初始化互斥鎖)
pthread_mutex_t mutex;
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr *mutexattr);
mutex [出參] 創建互斥鎖,會將新建的互斥鎖信息傳遞給mutex變量
mutexattr 互斥鎖屬性,默認為NULL
例:
pthread_mutex_init(&mutex, NULL); //創建并初始化互斥鎖
2 加鎖
一旦某個線程使用共享資源,就加鎖
int pthread_mutex_lock(pthread_mutex_t *mutex); //如果加鎖不成功(某個線程已經加鎖),阻塞
3 解鎖
int pthread_mutex_unlock(pthread_mutex_t *mutex); //如果某個線程正在等待加鎖,那么這線程進入就緒態
#include
#include
int a[10] = { 0 }; ///共享資源
int i;
pthread_mutex_t mutex;
void *fun1()
{
while(1)
{
int i;
pthread_mutex_lock(&mutex);
for(i = 0; i < 10; i++)
{
a[i] = i;
}
sleep(2);
for(i = 0; i < 10; i++)
{
printf("a[%d] is %d\n", i, a[i]);
}
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
void *fun2()
{
while(1)
{
sleep(1);
pthread_mutex_lock(&mutex);
for(i = 0; i < 10; i++)
{
a[i] = 1;
}
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t id1, id2;
pthread_mutex_init(&mutex, NULL);
pthread_create(&id1, NULL, fun1, NULL);
pthread_create(&id2, NULL, fun2, NULL);
pthread_join(id1, NULL);
}
////////信號量 (semaphore 簡寫 sem)
同樣可以解決共享資源互斥和同步的問題
信號量可以控制多個共享資源被訪問互斥的問題
#include
sem_t sem;
1 創建信號量(初始化信號量)
int sem_init(sem_t *sem, int pshared, int value);
sem [出參], 在創建信號量時,傳出的信號量結構體
pshared 通常寫0,代表此信號量在多線程之間使用
value 共享資源個數
sem_init(&sem, 0, 3);
sem_init(&sem, 0, 1);
sem_init(&sem, 0, 0);
2 請求信號量
sem_wait(&sem); //如果共享資源個數不為0, 請求成功,使用共享資源,然后共享資源個數-1
//當共享資源個數為0時,請求失敗,阻塞
3 釋放信號量
sem_post(&sem); //釋放信號量,如果有線程正在阻塞等待信號量,那么阻塞解除,
//如果沒有線程正在等待信號量,共享資源個數+1
四個線程共享信號量實例
sem_init(&sem, 0, 3); //表示共享資源個數有三個
線程A 調用sem_wait(&sem); //共享資源個數-1, 2
線程B 調用sem_wait(&sem); //共享資源個數-1, 1
線程C 調用sem_wait(&sem); //共享資源個數-1, 0
線程D 調用sem_wait(&sem); //共享資源個數已經為0, 線程D阻塞
如果線程A 調用sem_post(&sem); //線程D 解除阻塞
線程屬性
線程可以設置堆棧大小,可以設置線程優先級
默認情況堆棧大小(有些系統1M, 有些2M, 有些4M, 有些8M)
如果定義一個局部變量占用空間特別大,要改堆棧大小
測試線程堆棧大小
#include
#include
void *fun()
{
int a[1000000]; //約等于 4M 1M 1024k 1k 1024B
while(1)
{
printf("thread 1\n");
sleep(1);
}
}
int main()
{
pthread_t id1;
pthread_create(&id1, NULL, fun, NULL);
pthread_join(id1, NULL);
}
pthread_create(pthread_t *thread, pthread_attr_t *attr, void*(*start_routine)(void *), void *arg);
第二個參數 pthread_attr_t *attr; 線程屬性,默認NULL
1 獲得線程默認屬性,賦值給attr
pthread_attr_t attr;
pthread_attr_init(&attr); // 功能:獲取線程的默認屬性,會更改attr的值,給一個默認值
2 設置線程的堆棧大小屬性
pthread_attr_setstacksize(&attr, 14000000); ///功能:設置堆棧大小屬性
#include
#include
void *fun()
{
int a[1000000]; //約等于 4M 1M 1024k 1k 1024B
while(1)
{
printf("thread 1\n");
sleep(1);
}
}
int main()
{
pthread_t id1;
pthread_attr_t attr;
pthread_attr_init(&attr); // 功能:獲取線程的默認屬性,會更改attr的值,給一個默認值
pthread_attr_setstacksize(&attr, 14000000); ///功能:設置堆棧大小屬性
pthread_create(&id1, &attr, fun, NULL);
pthread_join(id1, NULL);
}