Linux应用编程---4.pthread_create函数

news2024/11/18 22:26:05

Linux应用编程—4.pthread_create函数

​ 之前学习了进程有关的东西,现在学习如何创建一个线程。

4.1 pthread_create()函数详情

​ 线程创建函数是:pthread_create()。在Linux终端下,输入man pthread_create,查看函数定义以及使用方法。

image-20221123220839209

图1 pthread_create函数详情
NAME
       pthread_create - create a new thread

SYNOPSIS
       #include <pthread.h>

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

       Compile and link with -pthread.

​ 简单来看,pthread_create是用来创建一个线程,使用时需要包含头文件:pthread.h。函数返回值是int型,有4个入参。特别注意编译时,要加上-pthread。

The  pthread_create()  function starts a new thread in the calling process.  The new thread starts execution by invoking start_routine(); arg is passed as the sole argu‐
       ment of start_routine().

​ pthread_create()函数在调用进程内开始一个新的线程。这个新的线程开始执行是通过调用start_routine()函数。arg作为start_routine()的唯一参数传递。

The attr argument points to a pthread_attr_t structure whose contents are used at thread creation time to determine attributes for the new thread; this structure is ini‐
       tialized using pthread_attr_init(3) and related functions.  If attr is NULL, then the thread is created with default attributes.
Before  returning,  a  successful  call  to  pthread_create() stores the ID of the new thread in the buffer pointed to by thread; this identifier is used to refer to the
       thread in subsequent calls to other pthreads functions.

​ pthread_create()有4个入参,分别是:pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg。在函数return前,pthread_create()成功调用,新的线程保存它的id号到指针指向的缓存也就是thread,所以,第一个参数传入一个pthread_t类型的地址,用来保存新的线程的id。这个id后面创建其它线程时起作用。attr参数指向pthread_attr_t类型的结构体指针,其内容是线程创建时用于确定新线程的属性。如果attr 时null的话,这个线程创建时是默认属性。void *(*start_routine) (void *)是一个函数指针,是新线程执行的函数入口,arg作为start_routine()的唯一参数传递,如果不需要传递参数,赋值NULL即可。

ETURN VALUE
       On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.

​ 有关返回值,当pthread_create()创建函数成功时,返回0。

​ 以上就是关于pthread_create()函数的用法。

4.2 pthread_create()函数编程实践

#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

void * thread_function(void *arg);

int main(void)
{
        int ret = 0;
        pthread_t thread;

        ret = pthread_create(&thread, NULL, thread_function, NULL);

        if(0 != ret)
        {
                perror("thread create.");
                exit(1);
        }

        return 0;
}

void * thread_function(void *arg)
{
        printf("Thread start running.\n");

        while(1)
        {
                printf("Hello world!\n");
                sleep(1);
        }
    
    return NULL;
}

​ 假如这个程序按照我们设想的方式执行,如果线程创建成功,则打印:Thread start running.Hello world每隔一秒钟打印一次。如果线程创建失败,则打印thread create.。但是,事实上运行结果是下图这样的:

image-20221123232533718

图2 代码运行结果

​ 没有任何现象!这是因为线程是从属于进程的。在线程创建结束后,main函数也执行到了return 0处,main函数就是调用进程,它结束后,系统资源被操作系统回收,线程也随之被回收。所以,运行没有结果。

​ 那么解决方法可以是,在线程没有执行结束后,进程要保持活跃的运行态。我们先简单粗暴的修改下代码。在main函数返回return 0之前,用while(1)将其阻塞。

image-20221123233219653

图3 用while(1)阻塞main函数

​ 此时,我们发现线程开始运行,每隔1秒打印一条语句。这里我们让进程保持运行状态,从而新建的线程也开始运行。但是,某些情况下,线程运行结束后,进程因为被while(1)阻塞,得不到释放。如何解决这个问题呢,在此,引入一个新的函数。

4.3 pthread_join()函数详情

​ 在终端输入man pthread_join,查阅该函数定义以及使用方法。

image-20221123233913927

图4 pthread_join函数详情
NAME
       pthread_join - join with a terminated thread

SYNOPSIS
       #include <pthread.h>

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

       Compile and link with -pthread.

​ pthread_join函数,返回值是int类型,函数调用成功时,返回值为0。入参有两个pthread_t thread, void **retval。

The  pthread_join() function waits for the thread specified by thread to terminate.  If that thread has already terminated, then pthread_join() returns immediately.  The
       thread specified by thread must be joinable.

       If retval is not NULL, then pthread_join() copies the exit status of the target thread (i.e., the value that the target thread supplied to pthread_exit(3)) into the  lo‐
       cation pointed to by retval.  If the target thread was canceled, then PTHREAD_CANCELED is placed in the location pointed to by retval.

​ pthread_join()函数用来等待线程结束,如果那个线程已经结束,该函数会立即返回。如果retval不为空指针,函数会将退出状态保存到retval里面。

#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

void * thread_function(void *arg);

int main(void)
{
        int ret = 0;
        pthread_t thread;

        ret = pthread_create(&thread, NULL, thread_function, NULL);

        if(0 != ret)
        {
                perror("thread create.");
                exit(1);
        }

        pthread_join(thread, NULL);

        return 0;
}

void * thread_function(void *arg)
{
        int i = 0;
        printf("Thread start running.\n");

        for(i = 0; i < 5; i++)
        {
                printf("Hello world!\n");
                sleep(1);
        }

        return NULL;
}

​ 该代码利用pthread_join(thread, NULL)监测线程结束,然后返回。也就是只有线程结束,才停止阻塞进程,让进程保持运行。

​ 运行结果:

image-20221124003245132

图5 运行结果

​ 当线程中的打印语句每隔1秒打印1次,一共打印了5次后,线程结束,随之,进程也结束。pthread_join(thread, NULL)起到了作用。

4.4 进阶

​ pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);arg作为start_routine()的唯一参数传递,那尝试用arg参数向进程传递参数。比如,传递线程中打印语句的打印次数。

#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

void * thread_function(void *arg);

int main(void)
{
        int ret = 0;
        pthread_t thread;
        int count = 7;

        ret = pthread_create(&thread, NULL, thread_function, &count);

        if(0 != ret)
        {
                perror("thread create.");
                exit(1);
        }

        pthread_join(thread, NULL);

        return 0;
}

void * thread_function(void *arg)
{
        int i = 0;
        printf("Thread start running.\n");

        for(i = 0; i < *((int *)arg); i++)
        {
                printf("Hello world!\n");
                sleep(1);
        }

        return NULL;
}

​ 运行结果:

image-20221124003852061

图6 运行结果

​ 我们定义了int型变量count,然后在pthread_create(&thread, NULL, thread_function, &count);中将其地址传入,在线程函数内,这个值被取出,并参与了循环终止条件的判断。根据结果来看,运行是正确的。

4.4 总结

​ 线程创建函数:pthread_create,以及它的入参的含义。线程是从属于进程的,进程结束线程也随之结束。阻塞式等待线程结束可以调用pthread_join()函数。
在这里插入图片描述

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

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

相关文章

Python基础(二十三):面向对象之继承介绍

文章目录 面向对象之继承介绍 一、继承的概念 二、单继承 三、多继承

IntelliJ IDEA安装教程(超详细)

✅作者简介&#xff1a;CSDN内容合伙人、阿里云专家博主、51CTO专家博主、新星计划第三季python赛道Top1&#x1f3c6; &#x1f4c3;个人主页&#xff1a;hacker707的csdn博客 &#x1f525;系列专栏&#xff1a;实用工具 &#x1f4ac;个人格言&#xff1a;不断的翻越一座又一…

Java学习(44)new关键字

new关键字 对象实例化 实例化对象的过程可以分为两部分&#xff1a; (1) 声明对象&#xff1a;Cat one (2) 实例化对象&#xff1a;new Cat()JVM可以被理解为Java程序与操作系统之间的桥梁 每次使用new关键字&#xff0c;就相当于在内存中开辟了一块新的存储空间。 package c…

CPU概述

CPU 概述 1. CPU 基础 CPU 的概念 CPU 是最重要的计算机组件&#xff0c;由控制器和运算器组成&#xff0c;通过总线与其它设备连接。 CPU 与南北桥 所谓的桥&#xff0c;都是 cpu 和其它设备连接这样的一个桥梁。分为南北桥。 什么是南桥&#xff1f; 南桥主要是用来连接…

【北邮果园大三上】运筹学期中后

运筹学后半段 第五章 动态规划 最优化原理&#xff0c;可以归结为一个递推公式 现实应用&#xff1a;比如最优路径、资源分配、生产计划和库存等 5.1 动态规划的最优化原理及其算法 5.1.1 求解多阶段决策过程的方法 例如&#xff1a;最短路径问题 求A到B的最短路径&#xff…

SpringBoot3.0集成SpringDoc2.0

SpringBoot3.0集成SpringDoc1. pom配置2. OpenApi配置类3. 使用4. SpringDoc注解与SpringFox对比5. 演示项目这里为什么要使用SpringDoc呢&#xff1f;是因为集成SpringFox只支持SpringBoot2.x&#xff0c; 而基于Swagger的SpringDoc的社区现在十分活跃&#xff0c;代码也在不断…

excel 设置双坐标轴柱状图

思路&#xff1a;通过添加辅助列来调整。 步骤&#xff11; 选中数据&#xff0c;插入柱状图&#xff0c;这时候会得到原始的柱状图 选中“设计”&#xff0d;“更改图表类型”&#xff0d;“组合”&#xff0c;调整图表类型均为柱状图&#xff0c;可以得到初始双坐标轴图表…

Linux应用编程---7.有名管道

Linux应用编程—7.有名管道 7.1 mkfifo函数详情 ​ 无名管道用于具有亲缘关系的进程之间通讯&#xff0c;比如&#xff1a;父子进程、兄弟进程。有名管道用于非亲缘关系进程之间的通讯。创建有名管道使用到的库函数是&#xff1a;mkfifo()&#xff0c;这里强调是库函数的原因…

Elasticsearch连续剧之基础篇

目录一、前言二、Elasticsearch数据结构三、安装1.配置最大可创建文件数大小2.由于ES不能以root用户运行&#xff0c;我们需要创建一个非root用户&#xff0c;此处创建一个名为es的用户3.安装es4.启动es服务四、常用操作1.创建没有结构的索引2.创建有结构的索引3.删除索引4.文档…

【迅为iMX6Q】开发板 u-boot 2020.04 RTL8211E 以太网驱动适配

相关参考 【迅为iMX6Q】开发板 u-boot 2015.04 SD卡 启动 【迅为iMX6Q】开发板 u-boot 2020.04 SD卡 启动 【迅为iMX6Q】开发板 u-boot 2022.04 SD卡 启动 开发环境 win10 64位 VMware Workstation Pro 16 ubuntu 22.04 【迅为imx6q】开发板&#xff0c; 2G DDR 目标 …

SAP Webservice 发布外网SAP端代理配置

前言 SAP Webservice接口发布外网的需求不算少见&#xff0c;一般是通过代理形式替换Webservice地址中的域名&#xff0c;但是完整的Webservice接口发布外网还需要以下步骤&#xff08;如果调用方在不做这些配置的情况下可以正常调用&#xff0c;则无需处理。&#xff09; 1. 配…

gravity 安装部署

gravity是由膜拜公司自主研发的不同数据库间数据同步工具。 官方介绍&#xff1a;https://github.com/moiot/gravity/blob/master/README-cn.md Gravity 是一款数据复制组件&#xff0c;提供全量、增量数据同步&#xff0c;以及向消息队列发布数据更新。 DRC 的设计目标是&a…

有电脑就可以干的工作有哪些?试试这些项目

现在几乎人人都有手机&#xff0c;吃饭时候看&#xff0c;睡觉的时候看&#xff0c;上个厕所也在看&#xff0c;有次坐地铁&#xff0c;发现很多上学的初中生、小学生都拿着手机&#xff0c;手机档次还挺高&#xff0c;都是最新的苹果、华为款的手机。反之再看看使用电脑的人又…

Linux——信号知识归纳(上)

一.信号概念&#xff08;一&#xff09;.大致认识信号是操作系统控制进程的一种方式&#xff0c;比如ctrl C、栈溢出程序崩溃、kill -9命令等底层都是操作系统发送信号给进程执行特定操作。因此&#xff0c;所有信号就底层而言都是操作系统发出的。同时&#xff0c;进程接收到信…

Java设计模式中桥接模式是什么/桥接模式有什么用,怎么运用桥接模式

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 5.5 桥接模式 5.5.1 定义 将抽象与实现分离&#xff0c;使他们可以独立变化&#xff0c;即用组合关系来代替继承关系实现&#xff0c;从而降低抽象与实现两个可变…

相参雷达(CSDN_0004_20220909)

文章编号&#xff1a;CSDN_0004_20220909 雷达信号处理中的一个基本操作是对样本进行积累&#xff0c;以提高SNR。积累的方式包括相参积累和非相参积累。相参积累是对复数信号&#xff08;既包括幅度又包括相位&#xff09;相加积累&#xff1b;非相参积累是对信号的幅度&#…

【时间复杂度与空间复杂度】衡量算法的标准,这篇文章让大家更深刻的理解时间复杂度和空间复杂度

前言&#xff1a; 大家好&#xff0c;我是良辰丫&#xff0c;今天和大家一起讨论一下时间复杂度与空间复杂度&#xff0c;往往来说&#xff0c;这两者是衡量算法好坏的标准&#xff0c;举个简单的例子&#xff0c;你想吃核桃了&#xff0c;用牙能弄开&#xff0c;用夹子也能弄开…

SAP灵活工作流场景配置及Demo测试

首先确保对应流程模板处于激活状态,并且事件已经激活 1. 在Fiori app 管理工作流中配置流程场景 地址&#xff1a;/sap/bc/ui2/flp?sap-client100&sap-languageZH#Workflow-showList 选择创建的灵活工作流模板&#xff0c;点击添加&#xff0c;开始配置场景 维护基本属性及…

JavaSE学习day2_02, IDEA的使用(重点)

4. idea 4.1 什么是idea&#xff1f; 是Java的集成开发工具&#xff0c;该工具把编写代码&#xff0c;编译&#xff0c;运行&#xff0c;调试等都集中在一起了。目前绝大多数企业编程用的执行环境. 特点&#xff1a; 自动保存、自动编译。 我们在使用的时候主要注重于两步…

SpringCloud微服务!!

目录 1.系统架构的演变 2.微服务简介 1.什么是微服务&#xff1f; 2.实现微服务的技术方案有哪些&#xff1f; 3.什么是SpringCloud? 4.微服务技术点【重点】 4.1服务治理、服务注册、服务发现 4.2 Eureka注册中心 4.2.1 Eureka介绍 4.2.2 Eureka 使用入门 4.2.3 Eureka的…