本文介绍: 1)线程在和不停的切换。2)每个线程都有自己的和1)是的最小单位,是操作最小单位2)线程上下文切换的比进程快得多3)从应用程序A中应用程序B才考虑使用

基础

1)线程运行就绪不停的切换
2)每个线程都有自己栈区寄存器

1)进程资源分配的最小单位线程操作系统调度执行的最小单位
2)线程的上下文切换的速度比进程快得多
3)从应用程序A中启用应用程序B才考虑使用多进程

线程API

线程创建
//每个线程都有唯一的线程ID,类型pthread_t,是一个符号长整形数
pthread_t pthread_self(void);	// 返回当前线程的线程ID
#include <pthread.h> //线程库的名字pthread, 全名: libpthread.so libptread.a
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
参数:
	thread:	传出参数,是无符号长整形数,线程创建成功, 会将线程ID写入这个指针指向内存attr:	线程的属性, 一般情况下使用默认属性即可,NULL
	start_routine: 函数指针创建出的子线程的处理动作,也就是该函数在子线程中执行arg: 	作为实参传递start_routine 指针指向函数内部
	返回值:	线程创建成功返回0,创建失败返回对应错误
-------------------创建线程 案列-----------------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

// 子线程的处理代码
void* working(void* arg)
{
    printf("我是子线程, 线程ID: %ldn", pthread_self());
    for(int i=0; i<9; ++i)
    {
        printf("child == i: = %dn", i);
    }
    return NULL;
}

int main()
{
    // 1. 创建一个子线程
    pthread_t tid;
    pthread_create(&amp;tid, NULL, working, NULL);
    printf("我是主线程, 线程ID: %ldn", pthread_self());    //子线程不会执行下边的代码, 主线程执行
    for(int i=0; i<3; ++i)
    {
        printf("i = %dn", i);
    }
    sleep(1); //主线程等待子线程执行完毕
    //如果主线程退出了, 虚拟地址空间就被释放了, 子线程就一并被销毁了。
    return 0;
}

执行

线程退出

1)想要让线程退出,但是不会导致虚拟地址空间的释放针对于主线程),可以调用线程库中线程退出函数
2)只要调用函数当前线程就马上退出,并且不会影响到其他线程的正常运行,不管是在子线程或者主线程中都可以使用

void pthread_exit(void *retval);
参数: 
	线程退出的时候携带的数据当前子线程的主线程会得到该数据。如果不需要使用,指定NULL
线程回收

1)这是一个阻塞函数, 子线程在运行这个函数阻塞
2)子线程退出, 函数解除阻塞, 回收对应的子线程资源, 类似于回收进程使用的函数 wait()

int pthread_join(pthread_t thread, void **retval);
参数:
	thread: 要被回收的子线程的线程ID
	retval: 二级指针, 指向一级指针的地址, 是一个传出参数, 这个地址存储pthread_exit() 传递出的数据,如果不需要这个参数可以指定NULL
	返回值:线程回收成功返回0回收失败返回错误号。

很多情况下还需要在主线程中回收子线程资源,所以主线程一般都是最后退出

子线程数据 回收

子线程退出的时候可以使用 pthread_exit()参数将数据传出,在回收这个子线程的时候可以通过 phread_join(pthread_t thread, void **retval) 的第二个参数来接收子线程传递出的数据

pthread_exit(void *retval);
-------------------子线程数据回收 案列-----------------------
// 定义结构
struct Persion{
    int id;
    char name[36];
    int age;
};

// 子线程的处理代码
void* working(void* arg){
    struct Persion* p = (struct Persion*)arg;
   // 使用主线程的栈内存
   p->age  =12;
   strcpy(p->name, "tom");
   p->id = 100;
   // 该函数的参数将这个地址传递给了主线程的pthread_join()
   pthread_exit(p);
    return NULL;
}

int main(){
    // 1. 创建一个子线程
    pthread_t tid;

    struct Persion p;
    // 主线程的栈内存传递给子线程
    pthread_create(&amp;tid, NULL, working, &amp;p);
    
    // 2. 子线程不会执行下边的代码, 主线程执行
    void* ptr = NULL;
    // ptr是一个传出参数, 在函数内部让这个指针指向一块有效内存
    // 这个内存地址就是pthread_exit() 参数指向的内存
    pthread_join(tid, &amp;ptr);// 会阻塞等待子线程退出,并回收资源
    
    // 打印信息
    printf("name: %s, age: %d, id: %dn", p.name, p.age, p.id);
    printf("子线程资源被成功回收...n");   
    return 0;
}

在这里插入图片描述

线程分离

子线程和主线程分离,当子线程退出的时候,其占用内核资源就被系统的其他进程接管并回收了。

// 参数就子线程的线程ID, 主线程就可以和这个子线程分离
int pthread_detach(pthread_t thread);
线程取消

在一个线程中杀死另一个线程。使用这个函数杀死一个线程需要分两步:
1)在线程A中调用线程取消函数pthread_cancel,指定杀死线程B,这时候线程B是死不了的
2)在线程B中进程一次系统调用(从用户区切换到内核区),否则线程B可以一直运行

// 参数是子线程的线程ID
int pthread_cancel(pthread_t thread);
参数:
	要杀死的线程的线程ID
	返回值:函数调用成功返回0调用失败返回非0错误号。

在这里插入图片描述

线程比较

在Linux中线程ID本质就是一个无符号长整形,可以直接使用比较操作符比较两个线程的ID,但是线程库是可以跨平台使用的。

int pthread_equal(pthread_t t1, pthread_t t2);
参数:
	t1 和 t2 是要比较的线程的线程ID
	返回值:如果两个线程ID相等返回非0值,如果不相等返回0

详细教程可转

爱编程的大丙

原文地址:https://blog.csdn.net/CYS_2020/article/details/134741562

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_33878.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注