多线程------线程的等待与分离

一、线程等待

// 函数原型
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

// 参数
           thread:线程ID
           retval:它指向一个指针,后者指向线程的返回值

//函数功能:等待线程结束

//返回值:成功返回0,失败返回错误码

写段代码看看等待和不等待之中主线程有啥区别
代码如下:
(1)等待

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void *thread_run(void * arg)
{
      int a = (int)arg;
      int count = 5;
      while (count--)
      {
            printf("new thread run:%lu,arg:%d\n", pthread_self(), a);
        sleep(1);
      }
}
 int main()
 {
      pthread_t t, t1, t2, t3;
      pthread_create(&t, NULL, thread_run, (void*)0);
      pthread_create(&t1, NULL, thread_run, (void*)1);
      pthread_create(&t2, NULL, thread_run, (void*)2);
      pthread_create(&t3, NULL, thread_run, (void*)3);

      pthread_join(t, NULL);
      pthread_join(t1, NULL);
      pthread_join(t2, NULL);
      pthread_join(t3, NULL);

    printf("main thread run......; tid :%lu\n", pthread_self());

      return 0;
}

运行之:
这里写图片描述
分析:
主线程先不跑,阻塞式的等待,等四个新线程跑完之后,主线程最后一个运行

(2)不等待

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void *thread_run(void * arg)
{
      int a = (int)arg;
      int count = 5;
      while (count--)
      {
            printf("new thread run:%lu,arg:%d\n", pthread_self(), a);
        sleep(1);
      }
}
 int main()
 {
      pthread_t t, t1, t2, t3;
      pthread_create(&t, NULL, thread_run, (void*)0);
      pthread_create(&t1, NULL, thread_run, (void*)1);
      pthread_create(&t2, NULL, thread_run, (void*)2);
      pthread_create(&t3, NULL, thread_run, (void*)3);

      //注释掉等待,看主线程不等待时会出现的情况
      //pthread_join(t, NULL);
      //pthread_join(t1, NULL);
      //pthread_join(t2, NULL);
      //pthread_join(t3, NULL);

    printf("main thread run......; tid :%lu\n", pthread_self());

      return 0;
}

运行之:
这里写图片描述

分析:
主线程直接退出,即从main函数里面return了,即进程退出了,即资源都没了,有关系线程的代码和数据都没了

话说为啥需要线程等待嘞?
(1)因为已经推出的线程,其空间没有被释放,仍然在进程的地址空间内
(2)创建新的线程不会复用刚才退出线程的地址空间

调用pthread_join的线程将被挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的状态是不同的。

* (1)如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值
* (2)如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元存放的是常数PTHREAD_CANCELED
* (3)如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数
* (4)如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数

二、分离线程
【例子:房子(大多数家庭资源共享,但也有个人的私有信息、私有物)、分家(分离:线程一旦分离,操作系统会分配一部分资源给分离出的线程)(分离出的线程挂掉之后,影响其他进程)】

不需要phread_jion回收的线程被称为分离线程
需要phread_jion回收的线程的称为可结合的线程(默认为结合的线程)

分离出的线程异常之后,进程依旧会被影响,被结束(因为它两同属于一个进程)

//函数原型
#include <pthread.h>
int pthread_detach(pthread_t thread);

// 返回值
成功返回0,失败返回错误码

// 线程自己分离自己
pthread_detach(pthread_self());

注:(1)线程组内其它成员对目标线程进行分离;也可以自己分离自己
(2)joinable和分离是冲突的,一个线程不能既是joinable又是分离的

为啥pid和进程id是一样的就是主线程?
答:因为当进程跑起来是,还没执行行任何操作的时候,进程和线程就已经有了,这个进程就可以被叫做只有一个执行流的进程

* 默认情况下,新创建的进程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,造成内存泄露
* 如果不关心线程的返回值,join是一种负担,此时,当线程退出时,系统自动释放线程资源

代码实现:
(1)线程被自己分离

#include<stdio.h>
#include<pthread.h>

void *pthread_run(void * arg)
{
      sleep(3);
      //(1) 线程自己分离自己
      pthread_detach(pthread_self());
      printf("detach done,%s\n",(char*)arg);

     pthread_exit((void*)0);

}

int main()
{
     pthread_t tid;

     pthread_create(&tid,NULL,pthread_run,"thread is runing");

     sleep(1);

     if(pthread_join(tid, NULL)==0)
     {
         printf("pthread join success!\n");
     }
     else
     {
         printf("pthread is failed\n");
     }
     return 0;
}

运行之:
这里写图片描述
(2)线程被别人分离(失败:不知道新线程和主线程那个先运行,调用失败,等待成功【时序问题】)
怎样保证设置成功

#include<stdio.h>
#include<pthread.h>

void *pthread_run(void * arg)
{
      sleep(3);

      printf("detach done,%s\n",(char*)arg);

     pthread_exit((void*)0);

}

int main()
{
     pthread_t tid;

     pthread_create(&tid,NULL,pthread_run,"thread is runing");
     //(2) 线程被别人分离
     pthread_detach(tid);

     sleep(1);

     if(pthread_join(tid, NULL)==0)
     {
         printf("pthread join success!\n");
     }
     else
     {
         printf("pthread is failed\n");
     }
     return 0;
}

(乍一看我们的程序写成功了,但运行是却不一定成功,因为在运行时我们不知道新线程和主线程哪个先运行,无法确定调用是否成功)

运行之:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/apt1203jn/article/details/80328809