进程线程-线程的创建和回收

本文详细介绍了Linux中的线程概念,包括进程与线程的区别,线程的特点,使用多线程的优势,以及如何在pthread库中创建、结束线程,处理线程间的参数传递和资源管理。重点讨论了线程分离的概念及其在提高程序效率方面的应用。
摘要由CSDN通过智能技术生成

1.线程介绍 

进程

        进程有独立的地址空间

        Linux为每个进程创建task_struct

        每个进程都参与内核调度,互不影响

线程

        进程在切换时系统开销大

        很多操作系统引入了轻量级进程LWP

        同一进程中的线程共享相同地址空间

        Linux不区分进程、线程

线程特点

        通常线程指的是共享相同地址空间的多个任务

使用多线程的好处

        大大提高了任务切换的效率

        避免了额外的TLB & cache的刷新

线程共享资源

一个进程中的多个线程共享以下资源:

        可执行的指令

        静态数据

        进程中打开的文件描述符

        当前工作目录

        用户ID

        用户组ID

线程私有资源

每个线程私有的资源包括:

        线程ID (TID)

        PC(程序计数器)和相关寄存器

        堆栈

        错误号 (errno)

        优先级

        执行状态和属性

Linux线程库

pthread线程库中提供了如下基本操作

        创建线程

        回收线程

        结束线程

2.线程的创建

#include  <pthread.h>
int  pthread_create(pthread_t *thread, const
       pthread_attr_t *attr, void *(*routine)(void *), void *arg);


pthread_t *thread:
这是一个指向pthread_t类型的指针,用于存储新创建线程的标识符。
pthread_t是一个线程ID的类型定义,它在pthread库中定义。
当pthread_create成功返回时,这个指针指向的位置将被设置为新线程的ID。

const pthread_attr_t *attr:
这是一个指向pthread_attr_t结构的指针,用于设置新线程的属性。
这个结构可以被用来设置各种线程属性,如堆栈大小、调度策略等。
如果这个参数被设置为NULL,那么将使用默认的线程属性。

void *(*routine)(void *):
这是一个函数指针,指向线程应该执行的函数。这个函数接受一个void *类型的参数,
并返回一个void *类型的值。这个返回值可以通过pthread_join函数来获取。

void *arg:
这是传递给线程函数的参数。它的类型是void *,所以你可以传递任何类型的指针给线程函数。
这个参数将被传递给上面提到的routine函数。

成功返回0,失败时返回错误码  thread 线程对象  attr 线程属性,NULL代表默认属性  routine 线程执行的函数  arg 传递给routine的参数 ,参数是void * ,注意传递参数格式

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
int* testThread(char* arg){
        printf("this is a thread test\n");
        return NULL;
}
int main(){
        pthread_t tid;
        int ret;
        ret = pthread_create(&tid,NULL,(void*)testThread,NULL);
        sleep(1);//需要等待线程完成才能看到线程的结果
        printf("ret=%d\n",ret);
        return 0;

}

注意事项:1. 主进程的退出,它创建的线程也会退出。

线程创建需要时间,如果主进程马上退出,那线程不能得到执行

编译线程创建的时候需要加 -lpthread

3.线程的结束

 #include  <pthread.h>
 void  pthread_exit(void *retval);

结束当前线程  

retval可被其他线程通过pthread_join获取 

线程私有资源被释放

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
int* testThread(char* arg){
        printf("this is a thread test\n");
        pthread_exit(NULL);
//一旦调用 pthread_exit,线程就会终止,后面的代码不会执行 
        printf("after exit\n");
}
int main(){
        pthread_t tid;
        int ret;
        ret = pthread_create(&tid,NULL,(void*)testThread,NULL);
        sleep(1);
        printf("ret=%d\n",ret);
        return 0;

}

4.线程查看tid函数

pthread_t  pthread_self(void)   查看自己的TID

#include <pthread.h>
pthread_t pthread_self(void);
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void* testThread(void* arg) {
        pthread_t self_tid = pthread_self();
        printf("This is a thread test, thread ID (pthread_self) = %p\n", (void*)self_tid);
        pthread_exit(NULL);
}

int main() {
        pthread_t tid;
        int ret;
        ret = pthread_create(&tid, NULL, testThread, NULL);
        if (ret != 0) {
                perror("Failed to create thread");
                return -1;
        }
        sleep(1);
        printf("Thread creation return value = %d\n", ret); // 这应该始终打印0,如果线程成功创建的话  
        printf("This is the main thread, thread ID (pthread_create return value) = %p\n", (void*)tid);
        pthread_join(tid, NULL);
        return 0;
}

5.线程查看命令

ps -eLf

6.线程间参数传递

1.通过地址传递参数,注意类型的转换

void *类型指针不能直接用*取值(*arg),因为编译不知道数据类型。

解决方法:转换为指定的指针类型后再用*取值  比如:*(int *)arg  将指针arg强转为int类型指针然后获取他所指向的值

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
void* testThread(void* arg){
        printf("this is test thread,tid=%lu\n",pthread_self());
        printf("input arg = %d\n",*(int*)arg);
        pthread_exit(NULL);

}
int main(){
        pthread_t tid;
        int ret;
        int arg = 5;
        ret = pthread_create(&tid,NULL,testThread,&arg);
        printf("this is main thread,tid=%lu",tid);
        sleep(1);
        return 0;
}

2.值传递,这时候编译器会告警,需要程序员自己保证数据长度正确

7.线程回收

#include  <pthread.h>
int  pthread_join(pthread_t thread, void **retval);

成功返回0,失败时返回错误码
thread 要回收的线程对象
调用线程阻塞直到thread结束
*retval 接收线程thread的返回值

注意:pthread_join 是阻塞函数,如果回收的线程没有结束,则一直等待

对于一个默认属性的线程 A 来说,线程占用的资源并不会因为执行结束而得到释放

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void* func(void* arg){
        printf("this is child thread\n");
        sleep(1);
        pthread_exit("thread return");
}
int main(){
        pthread_t tid;
        void *retv;
        pthread_create(&tid,NULL,func,NULL);
        pthread_join(tid,&retv);
        printf("thread ret=%s\n",(char*)retv);
        sleep(1);
        return 0;

}

8.线程分离

线程分离的作用主要是为了提高程序的执行效率和避免资源泄漏。

具体来说,线程分离允许主线程在创建新线程后,无需等待新线程的结束就可以继续执行自己的任务。这可以提高程序的并发性和响应性,特别是在主线程与新线程无关的情况下,可以避免主线程不必要的等待时间,从而提高整体的执行效率。

线程回收和线程分离是处理线程结束时的两种不同机制。

线程回收是自动进行的资源回收过程,而线程分离则允许线程在结束时立即释放资源并避免保留终止状态信息。选择使用哪种机制取决于具体的程序需求和系统环境。

1使用pthread_detach

int pthread_detach(pthread_t thread);    
成功:0;失败:错误号
指定该状态,线程主动与主控线程断开关系。线程结束后(不会产生僵尸线程)

或者

2 创建线程时候设置为分离属性

pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ARM小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值