TTTTTTZZZZZZ(系统编程---线程)11

创建近程属于系统调用。
创建线程属于库函数。

//看看这段代码
  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核数,就无法再执行加快了,而且还会影响速度

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值