Linux多线程-概念和控制(3)

简介: Linux多线程-概念和控制(3)

4、线程终止


终止线程的三种方法:

从线程函数return


线程可以调用pthread_ exit终止自己


线程可以调用pthread_ cancel终止同一进程中的另一个线程或者自己


注:在主线程使用return,以及在线程中使用exit都会终止整个进程


pthread_exit函数原型:


void pthread_exit(void *value_ptr);


解释:

功能:线程终止


参数:value_ptr线程退出传出的数据(不要指向一个局部变量)


返回值:无返回值,跟进程一样,线程结束的时候无法返回到它自身


注:pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了


pthread_cancel函数原型:


int pthread_cancel(pthread_t thread);


解释:

功能:取消一个执行中的线程


参数:thread表示要操作的线程的ID


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


注:pthread_cancel函数具有一定的延时性,并不会立即被处理,不建议当线程立即被创建后立即进行cancel取消(线程创建,并不会立即被调度);也不建议在线程退出前执行线程cancel取消(线程可能在取消之前就已经退出了);建议在线程执行中进行cancel取消线程


示例:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void *thread1(void *arg)
{
    printf("%s returning ... \n",(char*)arg);
    int *p = (int*)malloc(sizeof(int));
    *p = 1;
    return (void*)p;
}
void *thread2(void *arg)
{
    printf("%s exiting ...\n",(char*)arg);
    int *p = (int*)malloc(sizeof(int));
    *p = 2;
    pthread_exit((void*)p);
} 
void *thread3(void *arg)
{
    while ( 1 ){ //
        printf("%s is running ...\n",(char*)arg);
        sleep(1);
    } 
    return NULL;
} 
int main( void )
{
    pthread_t tid;
    void *ret;
    // thread 1 return
    pthread_create(&tid, NULL, thread1, (void*)"thread 1");
    pthread_join(tid, &ret);
    printf("thread 1 return, thread id %X, return code:%d\n", tid, *(int*)ret);
    free(ret);
    // thread 2 exit
    pthread_create(&tid, NULL, thread2, (void*)"thread 2");
    pthread_join(tid, &ret);
    printf("thread 2 exit, thread id %X, return code:%d\n", tid, *(int*)ret);
    free(ret);
    // thread 3 cancel by other
    pthread_create(&tid, NULL, thread3, (void*)"thread 3");
    sleep(3);
    pthread_cancel(tid);
    pthread_join(tid, &ret);
    if (ret == PTHREAD_CANCELED)
        printf("thread 3 cancel, thread id %X, return code: PTHREAD_CANCELED->%d\n", tid,ret);
    else
        printf("thread return, thread id %X, return code:%d\n", tid,ret);
    return 0;
}


5、线程等待


为什么需要线程等待:

已经退出的线程,其空间没有被释放,仍然在进程的地址空间内,创建新的线程不会复用刚才退出线程的地址空间,如果主线程不对新线程进行等待,那么这个新线程的资源也是不会被回收的。如果不等待会产生内存泄漏


线程是用来执行分配的任务的,如果主线程想知道任务完成的怎么样,那么就有必要对线程进行等待,获取线程退出的信息


pthread_join函数原型:


int pthread_join(pthread_t thread, void **value_ptr);


解释:

功能:等待线程结束


参数:thread:指定等待线程的ID;value_ptr:输出型参数,用来获取指向线程的返回值


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


注意:

调用该函数的线程将挂起等待,直到id为thread的线程终止


这里获取的线程退出信息并没有终止信号信息,而终止信号信息是对于整个进程来说的,如果线程收到信号崩溃也会导致整个进程也崩溃


thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的


终止获取的状态情况:

如果thread线程通过return返回,value_ ptr所指向的单元里存放的是thread线程函数的返回值


如果thread线程被别的线程调用pthread_ cancel异常终掉,value_ ptr所指向的单元里存放的是常数PTHREAD_ CANCELED


如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数


如果对thread线程的终止状态不感兴趣,可以传NULL给value_ ptr参数


示图:


示例:


#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
int val=0;
struct Ret 
{
    int exitno;
    int exittime;
    //...
};
void* Routine(void* avgs)
{
    int cnt=1;
    while(1)
    {
        printf("I am %s... val:%d\n",(char*)avgs,val);
        sleep(1);
        cnt++;
        if(cnt==3)
        {
            struct Ret* p=(struct Ret*)malloc(sizeof(struct Ret));
            p->exitno=0;
            p->exittime=6666;
            pthread_exit((void*)p);
            //pthread_cancel(pthread_self());
        }    
    }
}
int main()
{
    pthread_t tid1,tid2,tid3;
    pthread_create(&tid1,NULL,Routine,(void*)"pthread 1");
    pthread_create(&tid2,NULL,Routine,(void*)"pthread 2");
    pthread_create(&tid3,NULL,Routine,(void*)"pthread 3");
    int cnt=0;
    while(1)
    {
        printf("I am main pthread...val:%d\n",val++);
        sleep(1);
        cnt++;
        if(cnt==3)
            break;
    }
    printf("wait for pthread...\n");
    void* ret;
    pthread_join(tid1,&ret);
    printf("pthread id:%x exitno:%d exittime:%d\n",tid1,((struct Ret*)ret)->exitno,((struct Ret*)ret)->exittime);
    pthread_join(tid2,&ret);
    printf("pthread id:%x exitno:%d exittime:%d\n",tid2,((struct Ret*)ret)->exitno,((struct Ret*)ret)->exittime);
    pthread_join(tid3,&ret);
    printf("pthread id:%x exitno:%d exittime:%d\n",tid3,((struct Ret*)ret)->exitno,((struct Ret*)ret)->exittime);
    return 0;
}


6、线程分离


  • 概念:


默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏


如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源


pthread_detach函数原型:


int pthread_detach(pthread_t thread);


注意:


可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离: pthread_detach(pthread_self());


joinable和分离是冲突的,一个线程不能既是joinable又是分离的


线程的分离也是具有一定延时性,分离之后如果再进行等待那么得到返回的结果是未定义的


线程分离后只是回收的时候自动进行回收,如果主线程先退出,那么整个进程也会退出;如果分离的线程执行崩溃,同样的整个进行也会崩溃

示例:


#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* Routine (void* arg)
{
    pthread_detach(pthread_self());
    printf("%s detach success!\n");
    int cnt=0;
    while(cnt<5)
    {
        cnt++;
        printf("%s running...\n",(char*)arg);
        sleep(1);
    }
    printf("%s return...\n");
    return NULL;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid,NULL,Routine,(void*)"thread");
    sleep(2);//等待线程分离
    void* ret;
    if(pthread_join(tid,&ret)==0)
        printf("thread join success! ret:%d\n",(int*)ret);
    else 
        printf("thread join fail... ret:%d\n",(int*)ret);
    return 0;
}



相关文章
|
1月前
|
资源调度 Linux 调度
Linux C/C++之线程基础
这篇文章详细介绍了Linux下C/C++线程的基本概念、创建和管理线程的方法,以及线程同步的各种机制,并通过实例代码展示了线程同步技术的应用。
29 0
Linux C/C++之线程基础
|
1月前
|
Ubuntu Java Linux
Linux操作系统——概念扫盲I
Linux操作系统——概念扫盲I
43 4
|
1月前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
2月前
|
数据采集 消息中间件 并行计算
进程、线程与协程:并发执行的三种重要概念与应用
进程、线程与协程:并发执行的三种重要概念与应用
57 0
|
3月前
|
存储 缓存 Linux
在Linux中,文件系统概念是什么?
在Linux中,文件系统概念是什么?
|
3月前
|
存储 设计模式 NoSQL
Linux线程详解
Linux线程详解
|
3月前
|
缓存 前端开发 JavaScript
一篇文章助你搞懂java中的线程概念!纯干货,快收藏!
【8月更文挑战第11天】一篇文章助你搞懂java中的线程概念!纯干货,快收藏!
36 0
一篇文章助你搞懂java中的线程概念!纯干货,快收藏!
|
3月前
|
存储 安全 Linux
在Linux中,用户和组的概念是什么?
在Linux中,用户和组的概念是什么?
|
3月前
|
Linux 持续交付 虚拟化
在Linux中,Docker和容器虚拟概念是什么?
在Linux中,Docker和容器虚拟概念是什么?
|
3月前
|
负载均衡 Linux 调度
在Linux中,进程和线程有何作用?
在Linux中,进程和线程有何作用?