linux--(1)线程的创建与终止
# 线程基本概念
基本概念
进程是资源管理的最小单位,线程是程序执行的最小单位
进程都有自己的数据段、代码段和堆栈。占用资源比较多
所以演化出线程,花费更少的资源
线程与进程的关系是:线程是属于进程的
同一线程所产生的线程共享同一用户内存空间
一个进程至少需要一个线程作为他的指令执行体
进程管理者管理着资源(比如cpu,内存,文件)而将线程分配到某个cpu上执行
理解一下比如:车道 主线路分出其他子线路
线程分类
线程按其调度者可分为用户级线程和内核级线程
1.用户级线程:解决上下文切换的问题,由用户决定调度过程
2.内核级线程:由内核调度机制调度
大多是都用并存
实现线程的库
linux ------- pthread
linux中需要链接线程库pthread
线程标识
id
pthread_t数据类型
# 创建线程
完成案例:龟兔赛跑
#include<pthread.h> #include<stdio.h> #include<stdlib.h> int main() { int err;//定义错误存储 pthread_t rabbit,turtle;//定义线程标识符 //创建rabbit线程 if((err=pthread_create(&rabbit,NULL, th_fn,(void*)50))!=0){ perror("pthread_create error"); return 0; }
先讲一下这个创建线程几点
pthread_create(&rabbit,NULL,th_fn,(void*)50)
&rabbit是线程标识
NULL表示线程属性指针,表示没有这个
th_fn:线程运行函数
(void*)50:50转为指针,传递给线程运行函数的参数
-------------------------------------------------------------------
//drand48 返回服从均匀分布的·[0.0, 1.0) 之间的 double 型随机数。
源代码:
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <math.h> //定义线程运行函数 void* th_fn(void *arg) //传入void*数值 { int distance=(long)arg; //强转为int,我的是64位的long int i; for (i =1; i <=distance; i++) { printf("%lx run %d\n", pthread_self(),i); int time=(int)(drand48()*100000); usleep(time);//微秒 } return (void*)0; //返回指针 数值0 } int main() { int err;//定义错误存储 pthread_t rabbit,turtle;//定义线程标识符 //创建rabbit线程 if((err=pthread_create(&rabbit,NULL, th_fn,(void*)50))!=0){ perror("pthread_create error");} //创建turtle线程 if((err=pthread_create(&turtle,NULL, th_fn,(void*)50))!=0){ perror("pthread_create error");} sleep(10);//先睡眠主线程,先运行子线程 printf("control thread id: %lx\n",pthread_self()); //以十六进制输出主控线程id printf("fininshed!\n"); return 0; }
主线程结束后,碰到return 0就线程结束了,所以这里加一个sleep
运行
交叉运行
distance为50到50,停止
不能每次都这么好算sleep,sleep不好
所以接着换个方法 pthread_join
//主控线程调用pthread_join,自己阻塞 //直到rabbit和turtle线程结束才运行 pthread_join(rabbit,NULL); pthread_join(turtle,NULL);
效果一样的
接下来案例二:对第四个参数传递具体结构体
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <math.h> //定义结构体类型:新结构体 typedef struct { char name[20]; int time; int start; int end; }RaceArg; //定义运行函数 void* th_fn(void *arg){ RaceArg *r=(RaceArg*)arg; //强转为结构体指针类型 int i=r->start; for (; i <= r->end; i++) { printf("%s(%lx) running %d\n",r->name,pthread_self(), i); usleep(r->time); } return (void*)0; } int main(void) { int err; pthread_t rabbit,turtle; RaceArg r_a = { "rabbit",(int)(drand48()*100000000),20,50}; RaceArg t_a= {"turtle",(int)(drand48()*100000000),10,60}; if ((err=pthread_create(&rabbit,NULL,th_fn,(void*)&r_a))!=0){ perror("pthread_create error"); } if ((err=pthread_create(&turtle,NULL,th_fn,(void*)&t_a))!=0){ perror("pthread_create error"); } //主控线程调用pthread_join,自己阻塞, //直到rabbit和turtle线程结束才运行 pthread_join(rabbit,NULL); pthread_join(turtle,NULL); printf("control thread id: %lx\n",pthread_self()); //以十六进制输出主控线程id printf("fininshed!\n"); return 0; }
进程的内存分配
- 线程各自的变量保存在线程各自的栈空间中,互相独立
- 数据段的全局变量为共享资源,线程都可以访问更改,但是为线程不安全,需要把他变成线程安全。
- 多线程编程中推荐使用局部变量。
# 线程终止
线程终止的分类:
- 主动终止
- 线程的执行函数中调用return语句
- 调用pthread_exit()
- 被动终止
- 线程可以被同一进程的其他线程取消,其他线程调用pthread_cancel(pthid)
线程终止的函数
#include <pthread.h> int pthread_cancel(pthread_t tid); void pthread_exit(void *retval); int pthread_join(pthread_t th, void **thread_return); //返回值:成功返回0,否则返回错误编号
- pthread_cancel:
- 线程可以被同一进程的其他线程取消,tid为被终止的线程标识符,pthread_cancel()无法回收资源
- pthread_exit:
- retval: pthread_exit调用者线程的返回值,可由其他函数和pthread_join来检测获取。
- 线程退出时使用函数pthread_exit,是线程的主动行为。
- 由于一个进程中的多个线程共享数据段,因此通常在线程退出后,退出线程所占用的资源并不会随线程结束而释放。所以需要pthread_join函数来等待线程结束,类似于wait系统调用。
- pthread_join:
- th:被等待线程的标识符。
- thread_return:用户定义指针,用来存储被等待线程的返回值。
下面举几个例子:
案例1:二哥线程 id相加
#include <pthread.h> #include <stdlib.h> #include <stdio.h> typedef struct { int d1; int d2; }Arg; void* th_fn(void* arg) { Arg* r=(Arg*)arg; //强转为结构体指针 return (void*)(r->d1+r->d2); //输出是一个指针变量 返回指针 } int main(int argc, char **argv) { int err; pthread_t th; Arg r={20,50}; if(0!=(err = pthread_create(&th,NULL,th_fn,(void*)&r))) perror("pthread_create error"); //当返回为结构体指针 int *result; pthread_join(th, (void**)&result); //指针的指针 用户定义指针,用来存储被等待线程的返回值。 printf("result is %d\n",(int)result); //强转为int return 0; }
20+50=70,
这是一种方法
//当返回为结构体指针 // int *result; // pthread_join(th, (void**)&result); //指针的指针 用户定义指针,用来存储被等待线程的返回值。 // printf("result is %d\n ,(int)result); //强转为int int result; pthread_join(th,(void*)&result); printf("result is %d\n",result);
效果一样,返回到result到上 结果70指针、int 变为70
然后void*变为指针
修改返回类型,返回结构体指针
#include <pthread.h> #include <stdlib.h> #include <stdio.h> typedef struct { int d1; int d2; }Arg; void* th_fn(void* arg) { Arg* r=(Arg*)arg; //return (void*)(r->d1+r->d2); //输出是一个指针变量 return (void*)r; //输出一个结构体变量指针 } int main(int argc, char **argv) { int err; pthread_t th; Arg r={20,50}; if(0!=(err = pthread_create(&th,NULL,th_fn,(void*)&r))) perror("pthread_create error"); /* int *result; pthread_join(th, (void**)&result); //给th_fn返回的指针变量赋值 printf("result is %d\n",(int)result); */ /*或者 int result; pthread_join(th, (void*)&result); printf("result is %d\n",result); */ //当返回为结构体指针 int *result; pthread_join(th, (void**)&result); printf("result is %d\n",((Arg*)result)->d1+((Arg*)result)->d2); return 0; }
改进龟兔赛跑:
/* * pthread_creat2.c * 龟兔赛跑 */ #include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <math.h> #include <unistd.h> typedef struct { char name[10]; int time; int start; //起始点 int end; //结束点 }RaceArg; void* th_fn(void *arg) { RaceArg *r = (RaceArg*)arg; for(int i=r->start; i<=r->end; ++i) { printf("%s(%lx) running %d\n",r->name,pthread_self(), i); usleep(r->time); } //return (void*)0;//pthread_exit((void*)0); return (void*)(r->end - r->start); } int main(int argc, char **argv) { int err; //错误编码 pthread_t rabbit,turtle; //定义线程标识符 RaceArg r_a= {"rabbit", (int)(drand48()*10000000),20,50}; RaceArg t_a= {"turtle", (int)(drand48()*10000000),10,60}; if(0!=(err = pthread_create(&rabbit, NULL, th_fn, (void*)&r_a ))) //传入结构体指针 { perror("pthread_create error"); } if(0!=(err = pthread_create(&turtle, NULL, th_fn, (void*)&t_a ))) { perror("pthread_create error"); } int result; pthread_join(rabbit, (void*)&result); printf("rabbit race distance is %d\n", result); pthread_join(turtle, (void*)&result); printf("turtle race distance is %d\n", result); printf("race finished\n"); /* pthread_join(rabbit,NULL); pthread_join(turtle,NULL); */ printf("control thread ID: %lx\n",pthread_self()); printf("finished!\n"); return 0; }
输出:
turtle(b660c460) running 10 rabbit(b6e0d460) running 20 rabbit(b6e0d460) running 21 rabbit(b6e0d460) running 22 rabbit(b6e0d460) running 23 rabbit(b6e0d460) running 24 rabbit(b6e0d460) running 25 rabbit(b6e0d460) running 26 rabbit(b6e0d460) running 27 rabbit(b6e0d460) running 28 rabbit(b6e0d460) running 29 rabbit(b6e0d460) running 30 rabbit(b6e0d460) running 31 rabbit(b6e0d460) running 32 rabbit(b6e0d460) running 33 rabbit(b6e0d460) running 34 rabbit(b6e0d460) running 35 rabbit(b6e0d460) running 36 rabbit(b6e0d460) running 37 rabbit(b6e0d460) running 38 rabbit(b6e0d460) running 39 rabbit(b6e0d460) running 40 rabbit(b6e0d460) running 41 rabbit(b6e0d460) running 42 rabbit(b6e0d460) running 43 rabbit(b6e0d460) running 44 rabbit(b6e0d460) running 45 rabbit(b6e0d460) running 46 rabbit(b6e0d460) running 47 rabbit(b6e0d460) running 48 rabbit(b6e0d460) running 49 rabbit(b6e0d460) running 50 rabbit race distance is 30 turtle(b660c460) running 11 turtle(b660c460) running 12 turtle(b660c460) running 13 turtle(b660c460) running 14 turtle(b660c460) running 15 turtle(b660c460) running 16 turtle(b660c460) running 17 turtle(b660c460) running 18 turtle(b660c460) running 19 turtle(b660c460) running 20 turtle(b660c460) running 21 turtle(b660c460) running 22 turtle(b660c460) running 23 turtle(b660c460) running 24 turtle(b660c460) running 25 turtle(b660c460) running 26 turtle(b660c460) running 27 turtle(b660c460) running 28 turtle(b660c460) running 29 turtle(b660c460) running 30 turtle(b660c460) running 31 turtle(b660c460) running 32 turtle(b660c460) running 33 turtle(b660c460) running 34 turtle(b660c460) running 35 turtle(b660c460) running 36 turtle(b660c460) running 37 turtle(b660c460) running 38 turtle(b660c460) running 39 turtle(b660c460) running 40 turtle(b660c460) running 41 turtle(b660c460) running 42 turtle(b660c460) running 43 turtle(b660c460) running 44 turtle(b660c460) running 45 turtle(b660c460) running 46 turtle(b660c460) running 47 turtle(b660c460) running 48 turtle(b660c460) running 49 turtle(b660c460) running 50 turtle(b660c460) running 51 turtle(b660c460) running 52 turtle(b660c460) running 53 turtle(b660c460) running 54 turtle(b660c460) running 55 turtle(b660c460) running 56 turtle(b660c460) running 57 turtle(b660c460) running 58 turtle(b660c460) running 59 turtle(b660c460) running 60 turtle race distance is 50 race finished control thread ID: b6fe10b0 finished!
后续清理更新待写