线程,是一个并发的执行流程,一般称之为轻量级的进程。
线程从属于创建他的进程,不和进程分离,共享进程资源。
创建线程的进程结束了,该进程的所有简称都结束(皮之不存毛将焉附)。
线程是cpu最小的执行单元。
线程的创建:
//Linux Programmer`s Manual
#include<pthread.h>
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,
void *(*start_routine) (void *),void *arg);//创建一个新的线程
/*
参数1:线程的标识符(其实就是int) 参数2:设置线程的属性(分离or非分离)
参数3:线程要执行的函数(返回值和形参类型都固定死了(void *))
参数4:线程执行的时候,要传给线程的参数。
compile and link with -pthread 编译的时候要加上 -pthread
eg: gcc text.c -o s -pthread
成功返回0。
失败返回一个参数编号error number。
没有对全局错误变量设置值,不能用perror打印错误信息。(perror->errno)
可以把error number传到strerror()中获得错误信息。
分离:线程结束后,(进程)进行资源回收。
非分离:(进程)不进行资源回收。
*/
测试1: 主进程和2个线程并发执行>>>>>>>>>>>>>线程的创建。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void *thread_one(void *arg)
{
int num = (int)arg;
while(num > 0)
{
printf("int thread one ->%d\n",num--);
sleep(1);
}
return NULL;
}
void *thread_two(void *arg)
{
int num = (int)arg;
while(num > 0)
{
printf("int thread two ->%d\n",num--);
sleep(1);
}
return NULL;
}
int main(void)
{
//线程的标识
pthread_t one; //线程的标识符 long unsigned int
//参数2:设置线程的属性,分离,栈空间大小,优先级,调度策略..
//参数3:执行函数
//参数4:成功为0,失败为错误编号:注意 不是errno
int ret = pthread_create(&one,NULL,thread_one,(void*)10);
if(0 != ret)
{
printf("create thread one failed --> %s\n",strerror(ret));
//strerror()捕获错误信息,以字符串str类型返回。
//他不会设置全局错误变量,所以perror不能用。
//因为线程的创建函数不属于 系统调用,属于 用户层 的函数,所以不会对errno进行设置。
exit(EXIT_FAILURE);
}
printf("pthread_one=%lu\n", one);
pthread_t two;
int ret = pthread_create(&two,NULL,thread_two,(void*)15);
if(0 != ret)
{
printf("create thread one failed --> %s\n",strerror(ret));
exit(EXIT_FAILURE);
}
int i = 0;
//进程称之为主线程。
while(1)
{
printf("in main while -->%d\n",++i);
sleep(1);
} //第三个并发的执行流程。
return 0;
}
测试2:线程的结束。
线程的结束方式:
1,线程函数执行完了,运行return返回 (寿终正寝)
2,线程运行过程中,满足某个条件提前结束,pthread_exit (吊日子过不下去了)
3,线程A 收到 线程B 发送的结束请求,默认情况下,会结束执行结束请求,提前结束(谋害)
4,同归于尽的结束方式:在线程中调用exit。
1、2都是内部结束,3是外部结束。
线程结束处理:
线程有运行代码,有栈空间,TCB(线程控制块),线程号等...
线程结束后,需要对其进行资源回收。
---->pthread_join:阻塞等待指定的线程结束,并对其进行资源回收。
可以通过pthread_join 获得线程的返回值。
//man手册中的pthread_join
#include<pthread.h>
int pthread_join(pthiread_t thread,void **retval);
正常结束return:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void *thread_one(void *arg)
{
int num = (int)arg;
while(num > 0)
{
printf("int thread one ->%d\n",num--);
sleep(1);
}
return (void* 66);
}
int main(void)
{
//线程的标识
pthread_t one;
int ret = pthread_create(&one,NULL,thread_one,(void*)5);
if(0 != ret)
{
printf("create thread one failed --> %s\n",strerror(ret));
exit(EXIT_FAILURE);
}
printf("pthread_one =%lu\n",one);
//阻塞等待指定的线程结束,并对其进行资源回收
void *retval=NULL;
pthread_join(one,&retval);
printf("thread retval = %d\n",(int)retval);
int i = 0;
//进程称之为主线程。
while(1)
{
printf("in main while -->%d\n",++i);
sleep(1);
} //第三个并发的执行流程。
return 0;
}
非正常结束:
pthread_exit();
//man手册
#include<pthread.h>
void pthread_exit(void *retval);
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void *thread_one(void *arg)
{
int num = (int)arg;
while(num > 0)
{
printf("int thread one ->%d\n",num--);
sleep(1);
if(2==num)
{
//结束线程本身,不影响其他。
pthread_exit((void*)88);
}
}
printf("end of thread\n");
return (void* 66);
}
int main(void)
{
//线程的标识
pthread_t one;
int ret = pthread_create(&one,NULL,thread_one,(void*)5);
if(0 != ret)
{
printf("create thread one failed --> %s\n",strerror(ret));
exit(EXIT_FAILURE);
}
printf("pthread_one =%lu\n",one);
//阻塞等待指定的线程结束,并对其进行资源回收
void *retval=NULL;
pthread_join(one,&retval);
printf("thread retval = %d\n",(int)retval);
int i = 0;
//进程称之为主线程。
while(1)
{
printf("in main while -->%d\n",++i);
sleep(1);
} //第三个并发的执行流程。
return 0;
}
结束请求:
pthread_cancel();
//man手册
#include <pthread.h>
int pthread_cancel(pthread_t thread);
//成功返回0 失败返回 nonzero error number
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void *thread_one(void *arg)
{
int i = 0;
while(1)
{
printf("int thread one ->%d\n",++i);
sleep(1);
}
return (void* 66);
}
int main(void)
{
//线程的标识
pthread_t one;
int ret = pthread_create(&one,NULL,thread_one,NULL);
if(0 != ret)
{
printf("create thread one failed --> %s\n",strerror(ret));
exit(EXIT_FAILURE);
}
printf("pthread_one =%lu\n",one);
int i = 0;
//进程称之为主线程。
while(1)
{
printf("in main while -->%d\n",++i);
sleep(1);
if(5 == i)
{
//向指定的线程发出结束请求
pthread_cancel(one);
}
} //第三个并发的执行流程。
return 0;
}
线程对请求的处理:
pthread_setcaacelstate();
pthread_setcancelstate();
//man
#include<pthread.h>
int pthread_setcancelstate(int state,int *oldstate);
state:PTHREAD_CANCEL_ENABLE 允许接收请求(默认)
PTHREAD_CANCEL_DISABLE 阻塞
*oldstate: 是否要保存原先的state yes:任意int no:给NULL
返回值:成功返回0 不成功返回 nonzero error number
int pthread_setcanceltype(int type,int *oldtype);
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void *thread_one(void *arg)
{
int i = 0;
//收到的请求将会被阻塞,直到cancel的状态被设置为ENABLE
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
while(1)
{
printf("int thread one ->%d\n",++i);
sleep(1);
if(15 == i)
{
printf("15s解除阻塞..\n");
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
}
}
return (void* 66);
}
int main(void)
{
//线程的标识
pthread_t one;
int ret = pthread_create(&one,NULL,thread_one,NULL);
if(0 != ret)
{
printf("create thread one failed --> %s\n",strerror(ret));
exit(EXIT_FAILURE);
}
printf("pthread_one =%lu\n",one);
int i = 0;
//进程称之为主线程。
while(1)
{
printf("in main while -->%d\n",++i);
sleep(1);
if(5 == i)
{
//5S向指定的线程发出结束请求
printf("发送结束请求..\n");
pthread_cancel(one);
}
} //第三个并发的执行流程。
return 0;
}
线程属性的设置:
1.分离线程/非分离:
pthread_detach();//设置分离
//man
#include<pthread.h>
int pthread_detach(pthread_t thread);
//设置线程为分离线程,分离的线程结束后,资源自动回归系统,不需要等待资源回收
//如果分离一个已经分离的线程 会发生未知行为
成功返回0 不成功返货 nonzero error number
//获得线程号
pthread_self()
pthread_detach(pthread_self());//设置分离
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void *thread_one(void *arg)
{
pthread_detach(pthread_self());
int i = 0;
while(num > 0)
{
printf("int thread one ->%d\n",++i);
sleep(1);
if(5==i)
{
break;
}
}
return (void* 66);
}
int main(void)
{
//线程的标识
pthread_t one;
int ret = pthread_create(&one,NULL,thread_one,(void*)5);
if(0 != ret)
{
printf("create thread one failed --> %s\n",strerror(ret));
exit(EXIT_FAILURE);
}
printf("pthread_one =%lu\n",one);
//阻塞等待指定的线程结束,并对其进行资源回收
void *retval=NULL;
pthread_join(one,&retval);
printf("thread retval = %d\n",(int)retval);
int i = 0;
//进程称之为主线程。
while(1)
{
printf("in main while -->%d\n",++i);
sleep(1);
} //第三个并发的执行流程。
return 0;
}
以上程序还是join成功了,因为线程创建成功后,会先执行join(不能在join前sleep(1),若sleep(1)的话,会让出CPU去执行线程,就会先执行detach。然后再执行join),再执行detach!(detach写入线程内部的情况)
join失败:
在join之前设置线程分离。
pthread_detache(one);
//阻塞等待指定的线程结束,并对其进行资源回收
void *retval=NULL;
pthread_join(one,&retval);
printf("thread retval = %d\n",(int)retval);
**也可以在创建的时候 直接设置分离属性:
设置分离属性函数:pthread_attr_setdetachstate();
//man
#include<pthread.h>
pthread_attr_setdetachstate(pthread_attr_t *attr,int detachstate);
//detachstate:PTHREAD_CREATE_DETACHED
PTHREAD_CAEATE_DETACHED
pthread_attr_getdetachstate(pthread_attr_t *attr,int detachstate);//获得分离属性
pthread_attr_t attr; //设置属性的变量
pthread_attr_init(&attr);//初始化
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//生成分离属性
int ret = pthread_create(&one,&attr,thread_one,NULL);//设置分离
设置优先级:
//man
#include<pthread.h>
int pthread_attr_setschedparam(pthread_attr_t *attr,const struct sched_param *param);
int pthread_attr_getschedparam(pthread_attr_t *attr,const struct sched_param *param);
struct sched_param{
int sched_priority; //根据这个整数来确定优先级
}
pthread_attr_t attr; //设置属性的变量
pthread_attr_init(&attr);//初始化
struct sched_param param;
param.sched_priority = ;
pthread_attr_setschedparam(&attr,¶m);
if(0 != errnum)
{
printf("设置优先级失败--->%s\n",strerror(errnum));
exit(EXIT_FAILURE);
}
/*------------------------------------------------------------------------------------*/
笔记从2021.8.14开始记录。