1.线程的概述
进程--是我们程序的执行实例,进程在执行的时候,真正执行的就是进程中的线程,进程只是提供了线程执行的资源(PCB)。---进程包含线程
进程:进程指正在运行的程序。确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能。
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
例如:
进程---老板---》分配工作,分配资源的
线程--各部门工作人员--》干活,共用进程中的资源(PCB--进程控制块)
进程是分配资源的最小单位---重要
线程是程序执行的最小单元--重要
严格意义上,线程也是进程,他只是和进程不同的点,线程属于进程的,那么线程是不是可以共享进程的资源呢?---可以的
总结以下进程和线程的区别和联系:
不同线程是否可以共享全部的资源??
线程之间共享的内容:
1.代码
2.数据(进程中的)
3.进程空间
4.文件
不共享的内容:
1.寄存器
2.栈--线程中临时开辟的区域
线程和进程的比较:
多线程的应用场景:
应用主要方向---高并发服务器
QQ聊天室---
1.可以使用多进程编写
2.可以使用多线程编写
线程不属于系统中标准库的一部分,现成的使用需要调用其他的跟线程相关的库函数,如果需要去查看线程相关的函数定义,需要安装以下内容
在线手册安装:
sudo apt-get update
sudo apt-get install manpages-posix manpages-posix-dev
如果以上方法不行,尝试以下方法:
manpages 包含 GNU/Linux 的基本操作:
sudo apt-get install manpages
manpages-dev 包含 GNU/Linux 的基本操作API:
sudo apt-get install manpages-dev
manpages-posix 包含 POSIX 所定义公用程序的方法:
sudo apt-get install manpages-posix
manpages-posix-dev 包含 POSIX 的 header files 和 library calls 的用法:
sudo apt-get install manpages-posix-dev
在许多经典的操作系统教科书中, 总是把进程定义为程序的执行实例, 它并不执行什么, 只是维护应用程序所需的各种资源, 而线程则是真正的执行实体。 所以,线程是轻量级的进程(LWP: light weight process) , 在 Linux 环境下线程的本质仍是进程。 为了让进程完成一定的工作, 进程必须至少包含一个线程。
线程是进程的一个实体, 是 CPU 调度和分派的基本单位, 它是比进程更小的能独立运行的基本单位。
线程自己基本上不拥有系统资源, 只拥有一点在运行中必不可少的资源(如程序计数器, 一组寄存器和栈) , 但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
线程共享的资源和线程非共享的
共享资源:
1) 文件描述符表
2) 每种信号的处理方式
3) 当前工作目录
4) 用户 ID 和组 ID内存地址空间 (.text/.data/.bss/heap/共享库)
非共享资源:
1) 线程 id
2) 处理器现场和栈指针(内核栈)
3) 独立的栈空间(用户空间栈)
4)errno 变量
5) 信号屏蔽字
6) 调度优先级
线程的优缺点(了解)
优点:
- 提高程序并发性
- 开销小 --同一个进程中的不通线程共享资源
- 数据通信、 共享数据方便
缺点:
- 库函数, 不稳定
- 调试、 编写困难、 gdb 不支持
- 对信号支持不好
优点相对突出, 缺点均不是硬伤。 Linux 下由于实现方法导致进程、 线程差别不是很大。
2.线程的创建
线程号
进程号在整个系统中是唯一的, 但线程号不同, 线程号只在它所属的进程环境中有效。
线程号则用 pthread_t 数据类型来表示,Linux 使用无符号长整数表示。
获得线程号pthread_self():
#include <pthread.h>
pthread_t pthread_self(void);
功能:
获取线程号。
参数:
无
返回值:
调用线程的线程 ID
线程的创建
建议大家联系以下我们之前学习的RT_THREAD操作系统
#include <pthread.h>
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );
功能:
创建一个线程
参数:
thread: 线程标识符地址。
attr: 线程属性结构体地址(类似于进程的控制块), 通常设置为 NULL--默认,由系统分配。
start_routine: 线程函数的入口地址,线程创建完成之后,需要执行的操作。
arg: 传给线程函数的参数。
返回值:
成功: 0
失败: 非 0
start_routine所指向的函数定义格式
void *xxxxx(void *arg);
不同的线程也是可以执行相同的函数,也可以执行不同的函数
创建一个线程:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/
void *Pthread_func01(void *argv)
{
pthread_t pth_id;
printf("已经进入Pthread_func01\n");
// pth_id=pthread_self();
// printf("rev-->%s; pth_id-->%ld\n",(char *)argv,pth_id);
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
// sleep(2);
return NULL;
}
void *Pthread_func02(void *argv)
{
printf("已经进入Pthread_func02\n");
return NULL;
}
/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/
int main(void)
{
pthread_t p_th1;
int ret;
ret=pthread_create(&p_th1,NULL,Pthread_func01,"hello world");
if(ret!=0)
{
printf("线程创建失败\n");
// exit(-1);
}
getchar();
return 0;
}
创建多个线程,使用同一个线程执行函数:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/
void *Pthread_func01(void *argv)
{
pthread_t pth_id;
printf("已经进入Pthread_func\n");
// pth_id=pthread_self();
// printf("rev-->%s; pth_id-->%ld\n",(char *)argv,pth_id);
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
// sleep(2);
return NULL;
}
void *Pthread_func02(void *argv)
{
printf("已经进入Pthread_func02\n");
return NULL;
}
/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/
int main(void)
{
pthread_t p_th1,p_th2;
int ret;
ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
if(ret!=0)
{
printf("线程1创建失败\n");
// exit(-1);
}
ret=pthread_create(&p_th2,NULL,Pthread_func01,"p_th2:hello");
if(ret!=0)
{
printf("线程2创建失败\n");
// exit(-1);
}
getchar();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/
void *Pthread_func01(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
for(int i=0;i<5;i++)
{
sleep(1);
cout++;
printf("Pthread_func01 running is %d s\n",cout);
}
// sleep(2);
return NULL;
}
void *Pthread_func02(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
for(int i=0;i<7;i++)
{
sleep(1);
cout++;
printf("Pthread_func02 running is %d s\n",cout);
}
// sleep(2);
return NULL;
}
/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/
int main(void)
{
pthread_t p_th1,p_th2;
int ret;
ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
if(ret!=0)
{
printf("线程1创建失败\n");
// exit(-1);
}
ret=pthread_create(&p_th2,NULL,Pthread_func02,"p_th2:hello");
if(ret!=0)
{
printf("线程2创建失败\n");
// exit(-1);
}
while(1);
// getchar();
return 0;
}
查看线程数量
ps -ajx |grep a.out
ps -T p id
ps -T p id |wc -l 查看进程下的线程数
线程资源回收
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
功能:
等待线程结束(此函数会阻塞) , 并回收线程资源, 类似进程的 wait() 函数。
如果线程已经结束, 那么该函数会立即返回。
参数:
thread: 被等待的线程标识符。
retval: 用来存储线程退出状态的指针的地址
返回值:成功: 0失败: 非 0
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/
void *Pthread_func01(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
for(int i=0;i<5;i++)
{
sleep(1);
cout++;
printf("Pthread_func01 running is %d s\n",cout);
}
// sleep(2);
return "func01_exit";
}
void *Pthread_func02(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
for(int i=0;i<7;i++)
{
sleep(2);
cout++;
printf("Pthread_func02 running is %d s\n",cout);
}
// sleep(2);
return "func02_exit";
}
/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/
int main(void)
{
pthread_t p_th1,p_th2;
int ret;
ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
if(ret!=0)
{
printf("线程1创建失败\n");
// exit(-1);
}
ret=pthread_create(&p_th2,NULL,Pthread_func02,"p_th2:hello");
if(ret!=0)
{
printf("线程2创建失败\n");
// exit(-1);
}
//int pthread_join(pthread_t thread, void **retval);
char *func_str;
pthread_join(p_th1,&func_str);
printf("p_th1-->%s\n",(char *)func_str);
pthread_join(p_th2,&func_str);
printf("p_th2-->%s\n",(char *)func_str);
// while(1);
// getchar();
return 0;
线程分离:
线程属于进程的,分离--》将当前的线程和进程进行分离,分离之后的线程就是交给系统进行回收
#include <pthread.h>
int pthread_detach(pthread_t thread);
功能:
使调用线程与当前进程分离, 分离后不代表此线程不依赖与当前进程, 线程分离的目的是将线程资源的回收工作交由系统自动来完成, 也就是说当被分离的线程结束之后,系统会自动回收它的资源。 所以, 此函数不会阻塞
参数:
thread: 线程号。
返回值:
成功: 0
失败: 非 0
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/
void *Pthread_func01(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
for(int i=0;i<5;i++)
{
sleep(1);
cout++;
printf("Pthread_func01 running is %d s\n",cout);
}
// sleep(2);
return "func01_exit";
}
void *Pthread_func02(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
for(int i=0;i<7;i++)
{
sleep(2);
cout++;
printf("Pthread_func02 running is %d s\n",cout);
}
// sleep(2);
return "func02_exit";
}
/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/
int main(void)
{
pthread_t p_th1,p_th2;
int ret;
ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
if(ret!=0)
{
printf("线程1创建失败\n");
// exit(-1);
}
ret=pthread_create(&p_th2,NULL,Pthread_func02,"p_th2:hello");
if(ret!=0)
{
printf("线程2创建失败\n");
// exit(-1);
}
//int pthread_join(pthread_t thread, void **retval);
char *func_str;
pthread_join(p_th1,(void *)&func_str);
printf("p_th1-->%s\n",func_str);
// pthread_join(p_th2,(void *)&func_str);
// printf("p_th2-->%s\n",func_str);
//int pthread_detach(pthread_t thread);
pthread_detach(p_th2);
// while(1);
// getchar();
return 0;
}
3.线程的退出及取消
线程的退出:
#include <pthread.h>
void pthread_exit(void *retval);
功能:
退出调用线程。 一个进程中的多个线程是共享该进程的数据段, 因此, 通常线程退出
后所占用的资源并不会释放。
参数:
retval: 存储线程退出状态的指针。
返回值: 无
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/
void *Pthread_func01(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
for(int i=0;i<5;i++)
{
sleep(1);
cout++;
printf("Pthread_func01 running is %d s\n",cout);
}
// sleep(2);
return "func01_exit";
}
void *Pthread_func02(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
while(1)
{
sleep(1);
cout++;
printf("Pthread_func02 running is %d s\n",cout);
if(cout==7)
{
// void pthread_exit(void *retval);
pthread_exit("func02_pthread_exit");
}
}
// sleep(2);
return "func02_exit";
}
/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/
int main(void)
{
pthread_t p_th1,p_th2;
int ret;
ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
if(ret!=0)
{
printf("线程1创建失败\n");
// exit(-1);
}
ret=pthread_create(&p_th2,NULL,Pthread_func02,"p_th2:hello");
if(ret!=0)
{
printf("线程2创建失败\n");
// exit(-1);
}
//int pthread_join(pthread_t thread, void **retval);
char *func_str;
pthread_join(p_th1,(void *)&func_str);
printf("p_th1-->%s\n",func_str);
pthread_join(p_th2,(void *)&func_str);
printf("p_th2-->%s\n",func_str);
int pthread_detach(pthread_t thread);
// while(1);
// getchar();
return 0;
}
线程的取消
#include <pthread.h>
int pthread_cancel(pthread_t thread);
功能:
杀死(取消)线程
参数:
thread : 目标线程 ID。
返回值:
成功: 0
失败: 出错编号
设置取消点:
void pthread_testcancel(void);
在 Linux 系统下,线程默认可以被取消。编程时可以通过 pthread_setcancelstate
函数设置线程是否可以被取消。
pthread_setcancelstate(int state,int *old_state);
state:
PTHREAD_CANCEL_DISABLE:不可以被取消
PTHREAD_CANCEL_ENABLE:可以被取消。
old_state:
保存调用线程原来的可取消状态的内存地址。
注意: 线程的取消并不是实时的, 而又一定的延时。 需要等待线程到达某个取消点(检查点)。 类似于玩游戏存档, 必须到达指定的场所(存档点, 如: 客栈、 仓库、 城里等)才能存储进度。
杀死线程也不是立刻就能完成, 必须要到达取消点。取消点: 是线程检查是否被取消, 并按请求进行动作的一个位置。 通常是一些系统调用xxx_ creat, open, pause, close, read, write..... 执行命令 man 7 pthreads 可以查看具备这些取消点的系统调用列表。 可粗略认为一个系统调用(进入内核)即为一个取消点。
线程的取消点(man 7 pthreads)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/
void *Pthread_func01(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
for(int i=0;i<5;i++)
{
sleep(1);
cout++;
printf("Pthread_func01 running is %d s\n",cout);
}
// sleep(2);
return "func01_exit";
}
void *Pthread_func02(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//关闭取消点
// pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//开启取消点
for(int i=0;i<9;i++)
{
sleep(1);
cout++;
printf("Pthread_func02 running is %d s\n",cout);
}
// sleep(2);
return "func02_exit";
}
/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/
int main(void)
{
pthread_t p_th1,p_th2;
int ret;
ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
if(ret!=0)
{
printf("线程1创建失败\n");
// exit(-1);
}
ret=pthread_create(&p_th2,NULL,Pthread_func02,"p_th2:hello");
if(ret!=0)
{
printf("线程2创建失败\n");
// exit(-1);
}
//int pthread_join(pthread_t thread, void **retval);
char *func_str;
pthread_join(p_th1,(void *)&func_str);
printf("p_th1-->%s\n",func_str);
//int pthread_cancel(pthread_t thread);
sleep(1);
pthread_cancel(p_th2);
pthread_join(p_th2,(void *)&func_str);
printf("p_th2-->%s\n",func_str);
// int pthread_detach(pthread_t thread);
// while(1);
// getchar();
return 0;
}
4.线程的属性
线程是属于进程的,但是线程中的线程运行所需的栈空间和程序计数器等都是独立的,因此对于线程的属性也可以进行单独设置
typedef struct
{
int etachstate; //线程的分离状态
int schedpolicy; //线程调度策略
struct sched_param schedparam; //线程的调度参数
int inheritsched; //线程的继承性
int scope; //线程的作用域
size_t guardsize; //线程栈末尾的警戒缓冲区大小
int stackaddr_set; //线程的栈设置
void* stackaddr; //线程栈的位置
size_t stacksize; //线程栈的大小
} pthread_attr_t;
线程属性初始化及销毁
//线程属性初始化
int pthread_attr_init(pthread_attr_t *attr);
参数:
attr---线程属性,获取属性的地址
函数返回值:
成功:0;失败:错误号
//线程属性资源销毁
int pthread_attr_destroy(pthread_attr_t *attr);
函数返回值:成功:0;失败:错误号
通过属性进行线程分离:
线程分离状态的函数
设置线程属性,分离 or 非分离
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
获取程属性,分离or 非分离
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
参数:
attr:已初始化的线程属性
detachstate:
分离状态:
PTHREAD_CREATE_DETACHED(分离线程)
PTHREAD_CREATE_JOINABLE(非分离线程)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/
void *Pthread_func01(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
for(int i=0;i<5;i++)
{
sleep(1);
cout++;
printf("Pthread_func01 running is %d s\n",cout);
}
// sleep(2);
return "func01_exit";
}
void *Pthread_func02(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
// pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//关闭取消点
// pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//开启取消点
for(int i=0;i<9;i++)
{
sleep(1);
cout++;
printf("Pthread_func02 running is %d s\n",cout);
}
// sleep(2);
return "func02_exit";
}
/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/
int main(void)
{
pthread_t p_th1,p_th2;
int ret;
pthread_attr_t attr;
//初始化线程属性,获取属性的地址
//int pthread_attr_init(pthread_attr_t *attr);
pthread_attr_init(&attr);
//int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
ret=pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
if(ret==0)
{
printf("设置属性成功\n");
}
ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
if(ret!=0)
{
printf("线程1创建失败\n");
// exit(-1);
}
ret=pthread_create(&p_th2,&attr,Pthread_func02,"p_th2:hello");
if(ret!=0)
{
printf("线程2创建失败\n");
// exit(-1);
}
//int pthread_join(pthread_t thread, void **retval);
char *func_str;
pthread_join(p_th1,(void *)&func_str);
printf("p_th1-->%s\n",func_str);
//int pthread_cancel(pthread_t thread);
sleep(1);
pthread_cancel(p_th2);
pthread_join(p_th2,(void *)&func_str);
printf("p_th2-->%s\n",func_str);
// int pthread_detach(pthread_t thread);
// while(1);
// getchar();
return 0;
}
设置线程栈空间:
如果我们对程序的性能提出更高的要求那么需要设置线程属性, 比如可以通过设置线程栈的大小来降低内存的使用, 增加最大线程个数。
//设置栈的地址
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
attr:指向 pthread_attr_t 类型的指针,表示要设置的线程属性。
stackaddr:指向堆栈的起始地址的指针,可以使用 NULL 表示使用默认的堆栈。
stacksize:堆栈的大小,以字节为单位。
成功:0;失败:错误号
//得到栈的地址
int pthread_attr_getstack(pthread_attrt *attr, void **stackaddr, sizet*stacksize);
成功:0;失败:错误号
参数:
attr:指向一个线程属性的指针
stackaddr:返回获取的栈地址
stacksize:返回获取的栈大小
//设置线程所使用的栈空间大小
int pthread_attr_setstacksize(pthread_attr_t *attr, sizet stacksize);
成功:0;失败:错误号
//得到线程所使用的栈空间大小
int pthread_attr_getstacksize(pthread_attr_t*attr, size_t *stacksize);
成功:0;失败:错误号
参数:
attr:指向一个线程属性的指针
stacksize:返回线程的堆栈大小
栈空间大小的设置问题:
为什么设置大小为100个字节不行,但是17000就可以
单片机中学习flash的时候,学习的存储中的单位:块 扇区 页 页内大小
在我们的Ubuntu中,进程中默认的空间大小8M空间--可以修改
但是系统中每一个页的大小都是16KB--16384字节,每次去修改线程大小的时候,都必须要大于等于一个页,必须大于16KB
这也是导致我们开辟空间的时候,开辟100字节失败的原因
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
/*
pthread_t pthread_self(void);--线程ID
*/
void *Pthread_func01(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
for(int i=0;i<5;i++)
{
sleep(1);
cout++;
printf("Pthread_func01 running is %d s\n",cout);
}
// sleep(2);
return "func01_exit";
}
void *Pthread_func02(void *argv)
{
int cout=0;
pthread_t pth_id;
printf("pth_id-->%lu\n",pthread_self());
printf("rev-->%s\n",(char *)argv);
// pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);//关闭取消点
// pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//开启取消点
for(int i=0;i<9;i++)
{
sleep(1);
cout++;
printf("Pthread_func02 running is %d s\n",cout);
}
// sleep(2);
return "func02_exit";
}
/*
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg );--创建线程
*/
int main(void)
{
pthread_t p_th1,p_th2;
int ret;
int sta_stacksize;
pthread_attr_t attr;
//初始化线程属性,获取属性的地址
//int pthread_attr_init(pthread_attr_t *attr);
pthread_attr_init(&attr);
//int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
ret=pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
if(ret==0)
{
printf("设置属性成功\n");
}
//设置栈空间大小
//int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
void *sta_stack =calloc(1,17000);
ret= pthread_attr_setstack(&attr,sta_stack,17000);
if(ret==0){
printf("pthread_attr_setstack is ok\n");
// printf("sta_stacksize-->%d\n"sta_stacksize);
}
// int pthread_attr_getstack(pthread_attrt *attr, void **stackaddr, sizet*stacksize);
ret= pthread_attr_getstack(&attr,&sta_stack,(sizet*)&sta_stacksize);
if(ret==0){
printf("当前堆栈空间设置成功\n");
printf("sta_stacksize-->%d\n",sta_stacksize);
}
ret=pthread_create(&p_th1,NULL,Pthread_func01,"p_th1:hello");
if(ret!=0)
{
printf("线程1创建失败\n");
// exit(-1);
}
ret=pthread_create(&p_th2,&attr,Pthread_func02,"p_th2:hello");
if(ret!=0)
{
printf("线程2创建失败\n");
// exit(-1);
}
//int pthread_join(pthread_t thread, void **retval);
char *func_str;
pthread_join(p_th1,(void *)&func_str);
printf("p_th1-->%s\n",func_str);
//int pthread_cancel(pthread_t thread);
sleep(1);
pthread_cancel(p_th2);
pthread_join(p_th2,(void *)&func_str);
printf("p_th2-->%s\n",func_str);
// int pthread_detach(pthread_t thread);
// while(1);
// getchar();
return 0;
}
作业:
通过键盘输入创建线程,创建多线程,实现线程的计数(0-20),每一个线程的退出和资源回收;
标签:include,07,--,void,int,线程,pthread,概述,多线程 From: https://blog.csdn.net/weixin_46131184/article/details/136787372