线程的创建

news2025/2/26 13:34:09

1. 多线程常用函数

1.1 创建一条新线程pthread_create

在这里插入图片描述
对此函数使用注意以下几点:

  • 线程例程指的是:如果线程创建成功,则该线程会立即执行的函数。
  • POSIX线程库的所有API对返回值的处理原则一致:成功返回0,失败返回错误码errno.
  • 线程属性如果为NULL, 则会创建一个标准属性的线程,线程的属性非常多,有关线程的属性待研究

PTHREAD_CREATE_DETACHED 分离线程没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。
PTHREAD _CREATE_JOINABLE 线程的默认属性是非分离状态,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算。

1.2 线程的退出

线程跟进程类似,在缺省的状态下退出之后,会变成僵尸线程,并且保留退出值。其他线程可以通过相关 API 接合该线程——使其资源被系统回收,如果愿意的话还可以顺便获取其退出值。下面是相关 API:
在这里插入图片描述
在这里插入图片描述
线程执行完后如果不join的话,线程的资源会一直得不到释放而导致内存泄漏。
用上述函数需要注意以下几点:

  • 如果线程退出时没有退出值,那么 retval 可以指定为 NULL。
  • pthread_join( )指定的线程如果尚在运行,那么他将会阻塞等待。
  • pthread_tryjoin_np( )指定的线程如果尚在运行,那么他将会立即出错返回。

在某个时刻不能等某个线程“自然死亡”,而需要勒令其马上结束,此时可
以给线程发送一个取消请求,让其中断执行而退出。用到如下 API:
在这里插入图片描述

1.3 pthread_join/pthread_exit的用法解析

pthread_join 用于等待一个线程的结束,也就是主线程中要是加了这段代码,就会在加代码的位置卡主,直到这个线程执行完毕才往下走。
pthread_exit 用于强制退出一个线程(非执行完毕退出),一般用于线程内部。

一般都是 pthread_exit 在线程内退出,然后返回一个值。这个时候就跳到主线程的 pthread_join了(因为一直在等你结束),这个返回值会直接送到pthread_join,实现了主与分线程的通信。

2. 线程资源回收pthread_detach()函数的使用

每一个线程在任何情况,要么是可结合的状态(joinable),要么是可分离的状态(detached)。
两个函数的原型:

int pthread_join(pthread_t tid, void ** pthread_return);
int pthread_detach(pthread_t tid);

当线程运行结束后,最后显示的调用被回收。这样就出现两种回收方式。

  1. pthread_join 是一个阻塞函数,调用方会阻塞到 pthread_join 所指定的tid的线程结束后才被回收,但是在此之前,调用方是霸占系统资源的。
  2. pthread_detach,不会阻塞,调用它后,线程运行结束后会自动释放资源。
  3. 可分离的状态属性可以在pthread_create 时指定(线程属性),或在线程创建后在线程中pthread_detach自己, 如:pthread_detach(pthread_self()),将状态改为可分离的状态状态,确保资源的释放。或者将线程置为 joinable,然后适时调用pthread_join.

其实简单的说就是在线程函数头加上 pthread_detach(pthread_self())的话,线程状态改变,在函数尾部直接 pthread_exit线程就会自动退出。省去了给线程擦屁股的麻烦

PS:一个可结合线程在运行结束后,若没有调用 pthread_join,会进入一个类似zombie process 的状态,也就是系统中还有一些资源没有回收。需要pthread_join 来回收这些资源。(这就类似进程操作中的waitpid函数)线程在创建时默认的状态是 joinable, 如果一个线程结束运行但没有被join,则它的状态类似于进程中的Zombie Process(僵尸进程),即还有一部分资源没有被回收(退出状态码),所以创建线程者应该 pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于wait,waitpid),这样不会导致系统越用越慢的现象。
但是 pthread_join(pthread_id) 函数是阻塞函数,在调用pthread_join(pthread_id)后,如果该线程 没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此,比如在Web服务器中当 主线程 为每个新来的链接创建一个子线程进行处理的时候,主线程并不希望因为调用 pthread_join 而阻塞(因为还要继续处理之后到来的链接),这时可以在子线程中加入代码

pthread_detach( pthread_self());
或者父线程调用
pthread_detach(thread_id);(非阻塞,可立即返回)

这将该子线程的状态设置为detached,则该线程运行结束后会自动释放所有资源。
在嵌入式系统中,如果某些线程要伴随系统一直运行下去,该种情况下是否采用该该函数进行回收,没有什么价值。

3. 代码实例

/*
 * pthread_join()阻塞回收资源
 */
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void *thread1_func(void *arg)
{
    int n;    
    
    for (n = 0; n < 30; n++) {
        sleep(1);
        printf("AAAAAAAAAA\n");
    }
    pthread_exit(NULL);
    //return NULL;
}

void *thread2_func(void *arg)
{
    int n;
    for (n = 0; n < 30; n++) {
        sleep(1);
        printf("BBBBBBBBBB\n");
    }

    return NULL;
}

int main(int argc, char *argv[])
{
    pthread_t tid1, tid2;
    
    if (pthread_create(&tid1, NULL, thread1_func, NULL) != 0) {
        perror("main: pthread_create thread_1 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_1 succeed!\n");
    }

    if (pthread_create(&tid2, NULL, thread2_func, NULL) != 0) {
        perror("main: pthread_create thread_2 failed");
        return 1;
    } else {
        printf("main: pthread_create thread_2 succeed!\n");
    }
    
    if (pthread_join(tid1, NULL) != 0) {
        perror("main: pthread_join thread_1 failed");
    }
    if (pthread_join(tid2, NULL) != 0) {
        perror("main: pthread_join thread_2 failed");
    }
    
    printf("main is exiting.\n");
    
    return 0;
}

以下为一个多线程服务模型

/*
 * pthread_detach() 自动释放资源资源
 */
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/**
 * @brief 接收客户端发来的消息
 *        若客户端发来正常的消息便广播给其他应用,如客户端退出则删除对应客户端节点
 * @param ags 
 * @return void* 
 */
void *routine(void *ags) 
{
    //获取自己的TID, 进而分离自己;将来退出时立即释放资源
    pthread_detach(pthread_self());

    int connfd = (int)(*((int*)ags));

    char buf[SIZE];
    while (1)
    {
        bzero(buf, SIZE);
        //1. 关闭客户端或退出
        if (Read(connfd, buf, SIZE) == 0 || //read读取的是一个管道,如果对端关闭连接返回0
              !strcmp(buf, "quit\n")) 
        {
            del_client(connfd);
            break;
        }
        //2. 转发客户端的信息给到系统的其他客户端节点
        broad_cast(buf, connfd);
    }
    pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
    if (argc != 2) //外部动态输入端口号
    {
        printf("Usage: %s <PORT>\n", argv[0]);
        exit(0);
    }
    
    //TCP 创建套接字
    int sockfd = Socket(AF_INET, SOCK_STREAM, 0); //AF_INET:IPV4X协议 SOCK_STREAM:流式套接字
    
    struct sockaddr_in seraddr, cliaddr;
    socklen_t len = sizeof(seraddr);
    bzero(&seraddr, len);

    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(atoi(argv[1]));

    /*自动获取网卡地址*/
    seraddr.sin_addr.s_addr=htonl(INADDR_ANY);

    //绑定地址
    Bind(sockfd, (struct sockaddr *)&seraddr, len);
     
    //设置监听套接字
    Listen(sockfd, 3); //在linux中同时发起连接请求个数为3+4=7个

    while (1)
    {
        //持续等待对方连接,设置连接套接字,连接未建立完成处于阻塞中
        len = sizeof(cliaddr);
        int connfd = Accept(sockfd, (struct sockaddr *)&cliaddr, &len); //此处如需要保存客户端点地址信息,用 cliaddr接收,若不需要则为NULL
        
        char peeraddr[50];
        bzero(peeraddr, 50);
        printf("new connection: %s:%hu\n", 
                inet_ntop(AF_INET, &cliaddr.sin_addr, peeraddr, 50), 
                ntohs(cliaddr.sin_port)); // 打印客户端的IP地址和端口
        pthread_t tid;
        pthread_create(&tid, NULL, routine, (void *)&connfd); 
    }

    Close(sockfd);
 
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/347528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NLP实践——知识图谱问答模型FiD

NLP实践——知识图谱问答模型FiD0. 简介1. 模型结构2. 召回3. 问答4. 结合知识的问答0. 简介 好久没有更新了&#xff0c;今天介绍一个知识图谱问答&#xff08;KBQA&#xff09;模型&#xff0c;在此之前我一直在用huggingface的Pipeline中提供的QA模型&#xff0c;非常方便但…

低代码和零代码的有什么不同?如何区分?

低代码开发平台和零代码平台的区别是什么&#xff1f;一个例子就能讲清楚&#xff01; 周末你外出露营&#xff0c;在野外需要搭一个帐篷。有两种方法&#xff1a; 一种是最原始的搭帐篷方法&#xff0c;即有隔水布、外账、内账、营柱骨架等等......另一种是直接“封装好”的…

OpenCV-PyQT项目实战(5)项目案例01:图像模糊

欢迎关注『OpenCV-PyQT项目实战 Youcans』系列&#xff0c;持续更新中 OpenCV-PyQT项目实战&#xff08;1&#xff09;安装与环境配置 OpenCV-PyQT项目实战&#xff08;2&#xff09;QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战&#xff08;3&#xff09;信号与槽机制 …

PySpark实战一之入门

1、PySpark的编程模型 分三个模块&#xff1a; 数据输入&#xff1a;通过SparkContext对象&#xff0c;完成数据输入 数据处理计算&#xff1a;输入数据后得到RDD对象&#xff0c;对RDD对象的成员方法进行迭代计算 数据输出&#xff1a;最后通过RDD对象的成员方法&#xff0…

互联网行业固定资产智能化解决方案为企业降本增效

互联网行业的固定资产数量和种类往往比较多&#xff0c;来源可能是租赁、购入、调拨等。主要分为&#xff1a;办公设备、电子设备、服务器等。固定资产是互联网企业的重要资产之一&#xff0c;是企业持续经营的物质基础。因此&#xff0c;对于实物资产的管理尤为重要。 互联网…

搭建zookeeper高可用集群详细步骤

目录 一、虚拟机设置 1.新建一台虚拟机并克隆三台&#xff0c;配置自定义 2.修改四台虚拟机的主机名并立即生效 3.修改四台虚拟机的网络信息 4.重启四台虚拟机的网络服务并测试网络连接 5.重启四台虚拟机&#xff0c;启动后关闭四台虚拟机的防火墙 6.在第一台虚拟机的/e…

TripleCross:一款功能强大的Linux eBPF安全研究工具

关于TripleCross TripleCross是一款功能强大的Linux eBPF安全研究工具&#xff0c;该工具提供了后门、C2、代码库注入、执行劫持、持久化和隐蔽执行等功能。 功能介绍 1、使用一个代码库注入模块通过往进程的虚拟内存中写入命令来执行恶意代码&#xff1b; 2、提供了一个行劫…

波卡2022年第四季度报告

本文将介绍Messari最新发布的波卡Polkadot 2022年第四季度报告内容。 1 Messari已经发布关于波卡Polkadot最新的报告&#xff1a;显示了2022年第四季度的日活账户增加了64%&#xff0c;新用户增长49%。 2 Messari指出&#xff0c;波卡中继链在2022第四季度的环比增长令人印象…

JavaScript 保留关键字

文章目录JavaScript 保留关键字JavaScript 标准JavaScript 保留关键字JavaScript 对象、属性和方法Java 保留关键字Windows 保留关键字HTML 事件句柄非标准 JavaScriptJavaScript 保留关键字 在 JavaScript 中&#xff0c;一些标识符是保留关键字&#xff0c;不能用作变量名或函…

100行Pytorch代码实现三维重建技术神经辐射场 (NeRF)

提起三维重建技术&#xff0c;NeRF是一个绝对绕不过去的名字。这项逆天的技术&#xff0c;一经提出就被众多研究者所重视&#xff0c;对该技术进行深入研究并提出改进已经成为一个热点。不到两年的时间&#xff0c;NeRF及其变种已经成为重建领域的主流。本文通过100行的Pytorch…

部门新来个00后卷王,太让人崩溃了,想离职了....

在职场上&#xff0c;什么样的人最让人反感&#xff1f; 是技术不好的人吗&#xff1f; 并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗&#xff1f; 也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的…

【uniapp】getOpenerEventChannel().once 接收参数无效的解决方案

uniapp项目开发跨平台应用常会遇到接收参数无效的问题&#xff0c;无法判断是哪里出错了&#xff0c;这里是讲替代的方案&#xff0c;现有三种方案可选。 原因 一般我们是这样处理向另一个页面传参&#xff0c;代码是这样写的 //... let { title, type, rank } args; uni.n…

STM32 HAL库-定时器中断

STM32 HAL库-定时器中断一、STM32F407定时器介绍定时器计算公式二、CubeMX配置定时器三、基本定时器中断配置流程1&#xff09;开启定时器时钟2&#xff09;初始化定时器参数,设置自动重装值&#xff0c;分频系数&#xff0c;计数方式等3&#xff09;使能定时器更新中断&#x…

Ubuntu 系统 OpenCV 4 无法打开视频文件解决方案

目录 一、我的运行环境 二、问题描述 三、问题定位及分析 四、解决方案 一、我的运行环境 设备NVIDIA Jetson Nano处理器ARMv8 Processor rev 1 (v8l) 4 GPUNVIDIA Tegra X1 (nvgpu)/integrated操作系统ubuntu 18.04 LTSOpenCV版本4.6.0语言C 二、问题描述 之前一直用的O…

8 冒泡排序

文章目录1 基本介绍1 代码实现1.1 java1.1 scala1 基本介绍 冒泡排序&#xff08;Bubble Sorting&#xff09;的基本思想是&#xff1a;通过对待排序序列从前向后&#xff08;从下标较小的元素开始&#xff09;,依次比较相邻元素的值&#xff0c;若发现逆序则交换&#xff0c;使…

存储管理(6)

存储管理 1 程序的装入与链接 编译&#xff1a;源代码——目标代码 链接&#xff1a;目标代码所需库函数装入模块 装入&#xff1a;将装入模块装入内存&#xff0c;该过程也叫做地址重定位&#xff0c;也称地址映射 地址空间&#xff1a; 源程序经编译后得到的目标程序&…

Leetcode 1223. 掷骰子模拟【动态规划】

有一个骰子模拟器会每次投掷的时候生成一个 1 到 6 的随机数。 不过我们在使用它时有个约束&#xff0c;就是使得投掷骰子时&#xff0c;连续 掷出数字 i 的次数不能超过 rollMax[i]&#xff08;i 从 1 开始编号&#xff09;。 现在&#xff0c;给你一个整数数组 rollMax 和一…

WebDAV之葫芦儿·派盘+NMM

NMM 支持WebDAV方式连接葫芦儿派盘。 推荐一款文件管理器,可以对手机中的文件进行多方面的管理,支持语法高亮和ftp等远程的文件的管理。支持从WebDav服务器连接葫芦儿派盘服务下载文件和上传文件。 NMM文本编辑器是一款文件管理器,在功能上面更加的适合于一些编程人员进行使…

2023年应该了解的黑客知识

网络犯罪的艺术处于不断变化和演变的状态。与这些趋势保持同步是网络安全人员工作的重要组成部分。 今天的现代网络安全必须确保他们始终为下一个大趋势做好准备并保持领先于对手。 当我们开始迈向 2023 年时&#xff0c;安全格局与一年前相比已经发生了变化&#xff0c;更不…

Spark on hive Hive on spark

文章目录Spark on hive & Hive on sparkHive 架构与基本原理Spark on hiveHive on sparkSpark on hive & Hive on spark Hive 架构与基本原理 Hive 的核心部件主要是 User Interface&#xff08;1&#xff09;和 Driver&#xff08;3&#xff09;。而不论是元数据库&a…