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;
}



相关文章
|
17天前
|
Linux C++
LInux下Posix的传统线程示例
LInux下Posix的传统线程示例
15 1
|
25天前
|
消息中间件 存储 算法
【软件设计师备考 专题 】操作系统的内核(中断控制)、进程、线程概念
【软件设计师备考 专题 】操作系统的内核(中断控制)、进程、线程概念
68 0
|
24天前
|
算法 Unix Linux
Linux与Qt线程优先级的对应关系:一次全面解析
Linux与Qt线程优先级的对应关系:一次全面解析
21 0
|
10天前
|
算法 Java 开发者
Java中的多线程编程:概念、实现与性能优化
【4月更文挑战第9天】在Java编程中,多线程是一种强大的工具,它允许开发者创建并发执行的程序,提高系统的响应性和吞吐量。本文将深入探讨Java多线程的核心概念,包括线程的生命周期、线程同步机制以及线程池的使用。接着,我们将展示如何通过继承Thread类和实现Runnable接口来创建线程,并讨论各自的优缺点。此外,文章还将介绍高级主题,如死锁的预防、避免和检测,以及如何使用并发集合和原子变量来提高多线程程序的性能和安全性。最后,我们将提供一些实用的性能优化技巧,帮助开发者编写出更高效、更稳定的多线程应用程序。
|
1月前
|
缓存 Ubuntu 网络协议
Linux系统编程之文件I/O函数的使用:介绍文件I/O函数的基本概念、用法和实现方式
Linux系统编程之文件I/O函数的使用:介绍文件I/O函数的基本概念、用法和实现方式
20 1
|
25天前
|
消息中间件 Linux 调度
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
65 0
|
1月前
|
资源调度 算法 Linux
Linux进程/线程的调度机制介绍:详细解析Linux系统中进程/线程的调度优先级规则
Linux进程/线程的调度机制介绍:详细解析Linux系统中进程/线程的调度优先级规则
52 0
|
23天前
|
监控 Linux 调度
【Linux 应用开发 】Linux 下应用层线程优先级管理解析
【Linux 应用开发 】Linux 下应用层线程优先级管理解析
41 0
|
24天前
|
存储 算法 Linux
【Linux 系统标准 进程资源】Linux 创建一个最基本的进程所需的资源分析,以及线程资源与之的差异
【Linux 系统标准 进程资源】Linux 创建一个最基本的进程所需的资源分析,以及线程资源与之的差异
25 0
|
29天前
|
存储 安全 IDE
C/C++ 作用域,生命周期,执行线程的概念
C/C++ 作用域,生命周期,执行线程的概念
17 2