创建近程属于系统调用。
创建线程属于库函数。
//看看这段代码
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<pthread.h>
4 void* ThreadEntry(void* arg)
5 {
6 (void) arg;
7 while(1)
8 {
9 printf("In ThreadEntry\n");
10 sleep(1);
11 }
12 }
13 int main()
14 {
15 pthread_t tid;
16 pthread_create(&tid,NULL,ThreadEntry,NULL);
17 return 0;
18 }
运行结果如下:
根本就没有打印创建的子线程的内容,我们要知道,线程属于进程,并且主线程和创建的新线程属于,不同的执行流,这样的话,在执行新线程内部的操作的时候,主线程还在继续运行,此时假如主线程(进程)结束然后退出了,线程当然也不复存在 ,线程依赖于进程,进程退出,线程也不复存在了。
要想线程可以跑起来,那么在新创建的线程还没有运行结束的时候,进程就不能退出。
抢占式执行是引起线程麻烦的万恶之源。
现成的终止。
创建线程
pthread_create
结束线程
1.线程异常终止,那么进程也将崩溃,和进程异常终止属于一类
2.执行完毕,正常退出,平稳着落
a.让线程入口函数执行结束(最主要使用的结束方式)
b.pthread_exit(NULL),也能让本线程结束
假如你在线程中使用exit()函数来进行退出,那么无论你在哪个线程中去调用,整个进程都会直接退出。
3.pthread_cancel(tid,参数就是你要结束的线程id)可以让任意一个线程结束,但是必须是本进程中的线程。
但是不推荐使用
每一个线程也和进程类似,线程也会将自己的退出结果保存在pcb中,但是此时并不是等待父进程查看,而是所有的线程都可以查看到此进程的退出信息。
线程等待:
目的和进程等待类似,防止出现类似于僵尸进程的内存泄漏情况。
pthread_join: //线程等待,回收线程,
主要用于就是,某些逻辑需要创建的线程执行完毕之后,主线程才能继续运行,所以才会用到这个函数,给否则的话就是可以直接线程分离。
int pthread_join(pthread_t thread, void **retval); //只能根据线程PID来等待指定线程,而不同于wait(),只要参数为NULL就可以等待任意的子进程
thread:是你要等待的线程的PID,
retval:第二个是一个传入传出参数,传出的是一个void* 类型的参数,但是你可以无视,因为不用,可以直接填NULL
pthread_join(tid,NULL);tid为线程的id
但让pthread_join也是一个阻塞函数,只要线程没退出,他就在一直等待。
假如1号线程创建了2号线程,在1号线程中进行线程等待,假如2号线程不退出,1号线程就没有办法继续执行
线程分离:(线程分家,自生自灭)
//函数原型
int pthread_detach(pthread_t thread);
参数只有一个就是线程PID。
线程1创建了一个线程2,这个函数可以在线程2的内部调用,自己把自己分离出去,也可以在1号线程中调用,1号线程将2号线程分离出去
线程分离的目的,就是为了不用显示的回收线程,线程等待。
线程分离只是说不用关心这个线程的生死了,但是一旦主线程退出,这个被创建的线程就算还没有执行结束,还是得退出。
那既然有了线程分离之后,感觉pthread_join就没啥用了,其实不是
假如有这样一个应用场景:计算一个很大的矩阵相乘,可以使用多线程的方式来计算,每个线程计算其中的一部分结果,最后等到所有的线程都执行完了,由主线程汇总得到最终的结果,主线程就需要pthread_join来保证所有的线程都算完了,主线程才能继续执行。
============================================================================
//尝试使用一下线程
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<pthread.h>
4 typedef struct ADD
5 {
6 int a;
7 int b;
8 }ADD;
9 void* Created_thread(void* arg) //被创建的线程所执行的函数体
10 {
11 ADD* c = (ADD*)arg; //将传入的参数进行类型强壮
12 int d = c->a + c->b;
13 printf("%d\n",d);
14 return NULL; //返回NULL
15 }
16 int main()
17 {
18 pthread_t tid; //传出参数,获得线程的id
19 ADD arg ; //第四个参数,使用结构体传入多个参数
20 arg.a = 10;
21 arg.b = 10;
22 pthread_create(&tid,NULL,Created_thread,&arg); //创建线程
23 pthread_detach(tid); //线程分离
24 sleep(1); //为了保证创建的线程将事务执行完毕,这里睡一秒
25 printf("拜拜\n"); //主线程打印,然后结束
26 return 0;
27 }
强调一下,每个线程都有自己独立的调用栈,独立并不代表私有,私有的意思是其他线程不能获取到,而独立的意思是,其他线程也是可以获取到栈中的信息,只是相互独立开来,各自使用各自的数据,倘若想访问也是有办法的(比如第四个参数传参不就可以了吗)。
===========================================================================
验证多线程是利用多核资源的
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<pthread.h>
4 //3.多线程利用多核资源的
5 // 要验证有多核那么,一定要有多核
6 void* Created_thread(void* arg)
7 {
8 (void) arg;
9 while(1)
10 {}
11 return NULL;
12 }
13 int main()
14 {
15 pthread_t tid;
16 pthread_create(&tid,NULL,Created_thread,NULL);
17 while(1)
18 {}
19 return 0;
20 }
我的虚拟机现在是双核的,然后我跑下面这段代码的结果是,占用了200%,也就是说,多线程利用的是多核资源,但是当我再创建线程,继续跑的时候,因为我的虚拟机只有双核,所以此时再多的线程也只是200%,也是依赖硬件的。
所以说线程不是越多越好,达到一定的程度之后,cpu已经全部达到了上限之后,此时线程数如果继续增加,非但不能提高效率,反而会降低效率(线程多了,调度的开销也就更大了,效率也就会受到影响)
cpu密集型就是程序一运行起来,就进行大量的运算,这个比较吃cpu
io密集型就是程序一运行起来,就进行读写操作,不占cpu
到底该搞几个线程来进行高效的工作呢?
线程数目和工作的任务类型有关,究竟多少个合适,要通过测试的方法来确定。
===========================================================================
写一段利用多线程工作的代码,其实实现的功能很简单,就是将10000000个数据的数组中的每个元素乘 2 ,使用多线程来执行,就写了这么多的代码,多线程只是为了让计算机执行起来方便,但是写起来也太麻烦了。但是速度的提升是翻倍的。
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<pthread.h>
5 #include<time.h>
6 #include<sys/time.h>
7 #define pthread_size 2
8 #define MAX 100000000
9 void change(int* p,int begin,int end)
10 {
11 for(int i = begin ;i < end;++i)
12 {
13 p[i] = p[i] * 2;
14 }
15 }
16 typedef struct ARG
17 {
18 int begin;
19 int end;
20 int *p;
21 }ARG;
22 void* Created_thread(void* arg)
23 {
24 ARG* cc = (ARG*)arg;
25 change(cc->p,cc->begin,cc->end);
26 return NULL;
27 }
28 int gettime()
29 {
30 struct timeval tv;
31 gettimeofday(&tv,NULL);
32 return tv.tv_sec*1000000 + tv.tv_usec;
33 }
34 int main()
35 {
36 srand(time(NULL));
37 int* p = (int *)malloc(sizeof(int)*MAX);
38 int i;
39 for(i = 0; i < MAX;++i)
40 {
41 p[i] = i;
42 }
43 pthread_t tid[pthread_size] = {0};
44 ARG arg[pthread_size];
45 int c = 0;
46 for(i = 0; i < pthread_size;++i)
47 {
48 arg[i].begin = c;
49 arg[i].end =c + (MAX / pthread_size);
50 arg[i].p = p;
51 c = c + (MAX / pthread_size);
52 }
53 int64_t begin = gettime();
54 for(i = 0 ;i < pthread_size;++i)
55 {
56 pthread_create(&tid[i],NULL,Created_thread,&arg[i]);
57 }
58 pthread_join(tid[0],NULL);
59 pthread_join(tid[1],NULL);
60 int64_t end = gettime();
61 printf("%ld\n",end - begin);
62 return 0;
63 }
试了2,4,6,8,个线程,发现只要线程数超过cpu核数,就无法再执行加快了,而且还会影响速度