- 線程是程序中完成一個(gè)獨(dú)立任務(wù)的完整執(zhí)行序列,即一個(gè)可以調(diào)度的實(shí)體;進(jìn)程是資源分配和調(diào)度的一個(gè)獨(dú)立單位,線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分配的基本單位.
- 一個(gè)進(jìn)程至少擁有一個(gè)線程,在同一個(gè)進(jìn)程中的多個(gè)線程的內(nèi)存資源是共享的.由于共享地址空間,所以多線程之間沒有通信的必要,但必須要做好數(shù)據(jù)的同步和互斥.
- 并發(fā)是指在一個(gè)時(shí)間段內(nèi),多個(gè)任務(wù)交替進(jìn)行,雖然看起來像是同時(shí)執(zhí)行,但其實(shí)是交替的.
線程控制函數(shù)
1.
#include <pthread.h>
int pthread_create(pthread_t* thread,const pthread_attr_t* attr,void*(*start_routine)(void*),void* arg);
//成功時(shí)返回值為0,失敗則返回錯(cuò)誤碼
attr參數(shù)可以用于設(shè)置新線程的屬性,給它傳NULL,表示使用默認(rèn)線程屬性.start_routine和arg參數(shù)分別指定新線程將運(yùn)行的函數(shù)及其參數(shù).
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>
void* myfunc(void* arg)
{
//打印子線程的ID
printf("child thread ID= %ld\n",pthread_self());
return 0;
}
int main(int argc,const char* argv[])
{
//創(chuàng)建一個(gè)子線程
//線程ID變量
pthread_t pthid;
//返回錯(cuò)誤號(hào)
int ret=pthread_create(&pthid,NULL,myfunc,NULL);
if (ret!=0)
{
printf("error number:%d\n",ret);
//打印錯(cuò)誤信息
printf("%s\n",sterror(ret));
}
printf("parent thread ID= %ld\n",pthread_self());
for(int i=0;i<5;i++)
{
printf("I=%d\n",i);
}
sleep(2);
return 0;
}
運(yùn)行結(jié)果:
parent thread ID= 140594076149504
I=0
I=1
I=2
child thread ID= 140594068010752
I=3
I=4
2.
#include <pthread.h>
void pthread_exit(void *retval);
// 線程終止
pthread_exit可以通過retval參數(shù)向線程的回收者傳遞其退出的信息.
#include<pthread.h>
int pthread_join(pthread_t thread,void*retval);
pthread_join()函數(shù),以阻塞的方式等待thread指定的線程結(jié)束.當(dāng)函數(shù)返回時(shí),被等待線程的資源被收回.thread參數(shù)是目標(biāo)線程的標(biāo)識(shí)符,retval參數(shù)則是目標(biāo)線程返回的退出信息,該函數(shù)會(huì)一直阻塞,直到被回收的線程結(jié)束為止,函數(shù)成功時(shí)返回值為0,失敗則返回錯(cuò)誤碼.
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>
int num = 100; //堆內(nèi)存
void *myfunc(void *arg) {
//打印子線程的ID
printf("child thread ID= %ld\n", pthread_self());
for (int i = 0; i < 5; i++) {
printf("child I=%d\n", i);
if (i == 2) {
//退出攜帶信息
pthread_exit(&num);
}
}
}
int main(int argc, const char *argv[]) {
//創(chuàng)建一個(gè)子線程
//線程ID變量
pthread_t pthid;
//返回錯(cuò)誤號(hào)
int ret = pthread_create(&pthid, NULL, myfunc, NULL);
if (ret != 0) {
printf("error number:%d\n", ret);
//打印錯(cuò)誤信息
printf("%s\n", strerror(ret));
}
printf("parent thread ID= %ld\n", pthread_self());
//阻塞等待子線程的退出,并且回收pcb
void *ptr = NULL;
pthread_join(pthid, &ptr);
printf("number=%d\n", *(int *) ptr);
for (int i = 0; i < 5; i++) {
printf("parent I=%d\n", i);
}
return 0;
}
運(yùn)行結(jié)果:
parent thread ID= 140099126167296
child thread ID= 140099118028544
child I=0
child I=1
child I=2
number=100
parent I=0
parent I=1
parent I=2
parent I=3
parent I=4
3.
有時(shí)我們想要異常終止一個(gè)線程,即取消線程.
#include <pthread.h>
int pthread_cancel(pthread_t thread);
//成功時(shí)返回值為0,失敗則返回錯(cuò)誤碼
不過,接收到取消請(qǐng)求的目標(biāo)線程可以決定是否允許被取消以及如何取消,這分別由以下兩個(gè)函數(shù)來控制:
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldstate);
4.
常用的屬性:我們一般想要線程在結(jié)束時(shí),自動(dòng)釋放其線程資源,自動(dòng)回收pcb,則就需要給線程設(shè)置屬性為detach,即線程分離.設(shè)置完之后就不需要調(diào)用pthread_join再進(jìn)行線程回收了.
常用的函數(shù)與參數(shù):
函數(shù)原型: int pthread_detach(pthread_t pthid);
設(shè)置屬性類型:pthread_attr_t attr;
對(duì)線程屬性變量初始化:int pthread_attr_init(pthread_attr_t* attr);
設(shè)置屬性時(shí)通用做法:
代碼上,可以這樣表示:
pthread_t pthid;
pthread_attr_t attr; //線程屬性
pthread_attr_init(&attr); //初始化線程屬性
pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); //設(shè)置線程屬性
pthread_create( &pthid, &attr,myfunc, NULL); //建立線程
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>
void *myfunc(void *arg) {
//打印子線程的ID
printf("child thread ID= %ld\n", pthread_self());
for (int i = 0; i < 5; i++) {
printf("child I=%d\n", i);
if (i == 2) {
pthread_exit(NULL);
}
}
}
int main(int argc, const char *argv[]) {
//創(chuàng)建一個(gè)子線程
//線程ID變量
pthread_t pthid;
//返回錯(cuò)誤號(hào)
//初始化線程屬性
pthread_attr_t attr;
pthread_attr_init(&attr);
/* int pthread_attr_init(pthread_attr_t* attr);*/
//設(shè)置分離
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//創(chuàng)建線程時(shí)就設(shè)置線程分離
int ret = pthread_create(&pthid, &attr, myfunc, NULL);
if (ret != 0) {
printf("error number:%d\n", ret);
//打印錯(cuò)誤信息
printf("%s\n", strerror(ret));
}
printf("parent thread ID= %ld\n", pthread_self());
//退出主線程,子線程不受影響
//由于主線程退出,下面的不執(zhí)行
for (int i = 0; i < 5; i++) {
printf("parent I=%d\n", i);
}
sleep(2);
//釋放資源
pthread_attr_destroy(&attr);
return 0;
}
運(yùn)行結(jié)果:
parent thread ID= 139976127342336
parent I=0
child thread ID= 139976119203584
child I=0
child I=1
child I=2
parent I=1
parent I=2
parent I=3
parent I=4
5.
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>
void *myfunc(void *arg) {
int num = arg;
//打印子線程的ID
printf("%dth child thread ID= %ld\n", num, pthread_self());
return 0;
}
int main(int argc, const char *argv[]) {
//創(chuàng)建一個(gè)子線程
//線程ID變量
pthread_t pthid[5];
for (int i = 0; i < 5; i++) { //第四個(gè)參數(shù)傳遞的是按值傳遞,可以對(duì)子線程標(biāo)號(hào),而傳地址則不行,公用一個(gè)地址,注意此時(shí)不在為null了
/* pthread_create(&pthid[i],NULL,myfunc,(void*)&i);*/
pthread_create(&pthid[i], NULL, myfunc, (void *) i);
}
printf("parent thread ID= %ld\n", pthread_self());
for (int i = 0; i < 5; i++) {
printf("I=%d\n", i);
}
sleep(2);
return 0;
}
運(yùn)行結(jié)果:
1th child thread ID= 140415359592192
2th child thread ID= 140415351199488
0th child thread ID= 140415367984896
3th child thread ID= 140415342806784
4th child thread ID= 140415334414080
parent thread ID= 140415376123648
I=0
I=1
I=2
I=3
I=4