Linux——线程 二 (等待与分离)

线程等待:
为什么需要线程等待?
1.已经退出的线程,其空间没有被释放,仍然在进程的地址空间内
2.创建新的线程不会复用刚才退出的线程地址空间

我们知道进程内至少有一个线程作为执行单位,当我们进程退出了,意味着我们的线程也退出了。但是进程内有多个线程时,我们只想结束掉其中的某一个线程时,我们该如何做呢?系统为我们提供了下面几种方式:
1.从线程函数中直接调用 return ,这种方法对主线程不适用,从mian函数return相当于调用了exit,结束掉了整个进程。
2.线程可以调用pthread——exit() 终止自己
3.一个线程可以调用 pthread_cancel() 终止同一个进程中的另一个进程

看一下这两个函数的原型:

void  pthread_exit(void *value_ptr);

参数:value_ptr:value_ptr 不要指向一个局部变量
返回值:无

----------------------------

int pthread_cancel(pthread_t thread);

参数:thread(线程ID)
返回值: 成功返回0,失败返回错误码

进程中,如果父进程没有等待子进程返回的信息,那么会出现僵尸进程,而我们的线程也是如此。
进程中有 wait(),waitpid() 函数进行等待
线程中有 pthread_join()

int pthread_join(pthread_t thread, void **value_ptr);
参数:thread(线程ID)
    value_ptr:它指向一个指针,后者指向线程的返回值
返回值:成功返回0,失败返回错误码

调用该函数的线程将挂起等待,知道ID为thread的线程终止。我们知道线程的退出方式有几种,所以pthread_join() 得到的终止状态也是不同的。

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

线程等待实例:

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>

void *thread1(void *arg)
{
    printf("thread 1 return ...\n");
    int *p = (int *)malloc(sizeof(int));
    *p = 1;
    return (void *)p;                        //return 返回
}

void *thread2(void *arg)
{
    printf("thread 2 exit ...\n");
    int *p = (int *)malloc(sizeof(int));
    *p = 2;
    pthread_exit((void *)p);              //pthread_exit  退出
}

void *thread3(void* arg)
{
    while(1)
    {
        printf("thread 3 is running..\n");
        sleep(1);
    }
}
int main()
{
    pthread_t tid;
    void *ret;
    //线程1
    pthread_create(&tid,NULL,thread1,NULL);
    pthread_join(tid,&ret);
    printf("thread return , thread id %x,return code %d\n",tid,*(int *)ret);
    free(ret);


    //线程2
    pthread_create(&tid,NULL,thread2,NULL);
    pthread_join(tid,&ret);
    printf("thread return,thread id %x,return code %d\n",tid,*(int*)ret);
    free(ret);

    //线程3
    pthread_create(&tid,NULL,thread3,NULL);
    sleep(5);
    pthread_cancel(tid);                               //pthread_cancel 杀死3号线程
    pthread_join(tid,&ret);           
    if(ret == PTHREAD_CANCELED)
    {
        printf("thread return,thread id %x,return code PTHREAD_CANCELED\n",tid);
    }
     else{

        printf("thread return,thread id %x,return code NULL\n",tid);
     }

    return 0;
}

代码结果:
这里写图片描述

线程分离:

joinable: 可结合的
detach:可分离的

为什么需要线程分离?
1.默认情况下,新创建的线程是 joinable 的,线程退出后,需要对其进行 pthread_join 操作,否则无法释放资源,从而造成内存泄露。
2.如果我们不关心线程的返回值,调用 pthread_join() 是一种负担,这时,我们可以告诉系统,当线程退出时,自动的释放线程的资源。

函数有两个:

线程组内其他线程对目标线程进行分离:
int pthread_detach(pthread_t thread);


线程自己分离:
pthread_detach(pthread_self());
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>

void *thread(void *arg)
{
    pthread_detach(pthread_self());           //自己分离
    printf("thread running ...\n");
    return NULL;
}

int main()
{
    pthread_t tid;
    if(pthread_create(&tid,NULL,thread,NULL) != 0)
    {
        printf("pthread_create  failed\n");
        return 1;
    }

    int ret = 0;
    sleep(1);

    if(pthread_join(tid,NULL) == 0)                    //等待,但是线程已经分离,资源被回收了,等待失败
    { 
        printf("pthread wait success \n");
        ret = 0;
    }
    else{
        printf("pthread wait failed \n");
        ret = 1;
    }

    return ret;
}

这里写图片描述

ps:
对比进程和线程的函数:


进程                          线程
pid                     pthread
fork()                  pthread_create
wait()                  pthread_join
僵尸进程                 僵线程
exit                    pthread_exit
kill                    //他杀  int pthread_cancel(tid)   cancel,线程不会立即退出,而是要等到取消点才退出
                            取消点:凡是系统调用的地方都是取消点
                            人为设置一个取消点:void pthread_testcancel(void)

猜你喜欢

转载自blog.csdn.net/shawei_/article/details/81305073