C语言多线程基础(pthread)

1.线程和进程的概念

  • 线程:进程中的一个实体,是CPU调度和分派的基本单位。可以与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一进程中的多个线程之间可以并发执行,线程在运行中呈现间断性。
  • 进程:具有一定独立功能的程序关于数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。进程是一个可拥有资源的独立单位,可以独立调度和分派的基本单位。

 

 2. 线程的创建pthread_create()

#include <pthread.h>//需要添加pthread.h头文件
int pthread_create(pthread_t *thread,   //指向线程标识符的指针,用pthread_t创建const pthread_attr_t *attr,  //设置线程属性,默认为NULLvoid *(*start_rtn)(void *), //线程运行函数的起始地址void *arg //传递给线程函数的参数);

创建一个基本的线程程序如下main.cpp:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>void* ptintf_hello_world(void* tid);int main(void){pthread_t thread;int status;int i = 10;printf("Main here. Creating thread %d\n",i);status=pthread_create(&thread, NULL, ptintf_hello_world, &i); pthread_join(thread,NULL);  //pthread_join函数以阻塞的方式等待指定的线程结束,如果线程已经结束,函数会立即返回	if(status!=0){printf("pthread_create returned error code %d\n", status);exit(-1);}exit(0);
}
void* ptintf_hello_world(void* tid){printf("Hello world %d.\n", *(int*)tid);exit(0);
}

Android.mk :

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)LOCAL_CFLAGS += -DAWINIC_DEBUG
LOCAL_VENDOR_MODULE := true
LOCAL_LDLIBS    := -llogLOCAL_SRC_FILES := main.cpp
LOCAL_MODULE := addValTest
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := falseinclude $(BUILD_EXECUTABLE)

 Application.mk:

APP_PLATFORM := android-26
APP_ABI := arm64-v8a, armeabi-v7a
APP_STL := c++_static

创建jni文件夹,然后将main.cpp、Android.mk 、Application.mk三个文件放入jni文件夹下,然后再jni同级目录打开cmd窗口,执行ndk-build,即可生成可执行文件addValTest,然后push到手机system/bin目录下执行:

3. 等待线程结束pthread_join()

先看下面程序:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUMBER_OF_THREADS 10void* ptintf_hello_world(void* tid);
int main(void){pthread_t threads[NUMBER_OF_THREADS];int status = 0;int i = 0;for(i=0; i < NUMBER_OF_THREADS; i++){//循环创建10个线程printf("Main here. Creating thread %d\n",i);//创建线程,线程函数传入参数为istatus = pthread_create(&threads[i], NULL,ptintf_hello_world, &i);if(status != 0){//线程创建不成功,打印错误信息printf("pthread_create returned error code %d\n", status);exit(-1);}}exit(0);
}
void* ptintf_hello_world(void* tid){printf("Hello world %d.\n", *(int*)tid);//在线程函数中打印函数的参数pthread_exit(0);
}

运行结果:

由于我们没有在主线程中等待我们创建出来的10个线程执行完毕,所以创建出来的子线程可能还没来得及执行,就因为主线程(main函数)执行完毕而终止整个进程,导致子线程没法运行。因此printf得到的“Hello world”不是10个,其数量是无法预知的,其顺序也是无法预知的。而且传的是地址,子线程在执行时,i值可能还没更新,所以可能会打印重复的值。

此时我们就需要pthread_join()函数来等待线程执行完成。

pthread_join()函数的原型如下:

int pthread_join(pthread_t thread,    //线程标识符,即线程ID,标识唯一线程void **retval);    //用户定义的指针,用来存储被等待线程的返回值。
//返回值:0:成功;其他:失败的错误号

使用pthread_join()函数之后的代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUMBER_OF_THREADS 10void* ptintf_hello_world(void* tid);
int main(void){pthread_t threads[NUMBER_OF_THREADS];int status = 0;int i = 0;for(i=0; i < NUMBER_OF_THREADS; i++){//循环创建10个现场printf("Main here. Creating thread %d\n",i);//创建线程,线程函数传入参数为istatus=pthread_create(&threads[i], NULL, ptintf_hello_world, &i);if(status != 0){//线程创建不成功,打印错误信息printf("pthread_create returned error code %d\n", status);exit(-1);}}for(i=0; i < NUMBER_OF_THREADS; i++){pthread_join(threads[i], NULL);}exit(0);
}
void* ptintf_hello_world(void* tid){printf("Hello world %d.\n", *(int*)tid);//在线程函数中打印函数的参数pthread_exit(0);
}

可以看出,此时所有子线程都执行完毕,打印了10个。但是线程执行的顺序是不固定的,也就是说我们无法预知打印的顺序。根据代码判断程序的输出是不可行的,我们只知道输出的内容,但不知道输出的顺序。

除非我们在每个子线程创建之后,一直等其运行结束,然后才开始创建下一个子线程。即将pthread_join()函数放到紧挨着pthread_create()函数的后面,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUMBER_OF_THREADS 10void* ptintf_hello_world(void* tid);
int main(void){pthread_t threads[NUMBER_OF_THREADS];int status = 0;int i = 0;for(i=0; i < NUMBER_OF_THREADS; i++){//循环创建10个现场printf("Main here. Creating thread %d\n",i);//创建线程,线程函数传入参数为istatus=pthread_create(&threads[i], NULL, ptintf_hello_world, &i);pthread_join(threads[i], NULL);if(status!=0){//线程创建不成功,打印错误信息printf("pthread_create returned error code %d\n",status);exit(-1);}}exit(0);
}
void* ptintf_hello_world(void* tid){printf("Hello world %d.\n", *(int*)tid);//在线程函数中打印函数的参数pthread_exit(0);
}

运行结果如下: 

4. 使用pthread_join()得到线程函数的返回值

使用pthread_join()除了有阻塞线程功能之外,还可以利用其第二个参数,得到线程函数的返回值。代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUMBER_OF_THREADS 10void* ptintf_hello_world(void* tid);
int main(void){pthread_t threads[NUMBER_OF_THREADS];int status = 0;int i = 0;for(i=0; i<NUMBER_OF_THREADS; i++){printf("Main here. Creating thread %d\n",i);status = pthread_create(&threads[i], NULL, ptintf_hello_world, &i);//使用res得到线程函数的返回值 int** res=(int**)malloc(sizeof(int*));pthread_join(threads[i],(void**)res);  //pthread_join函数以阻塞的方式等待指定的线程结束printf("res[%d]:%d\n",i,**res);//打印线程函数的返回值 free(*res); //释放线程处理函数中使用malloc分配的内存空间 if(status!=0){printf("pthread_create returned error code %d\n",status);exit(-1);}}exit(0);
}
void* ptintf_hello_world(void* tid){int val = *(int*)tid;printf("Hello world %d.\n", val);int* a=(int*)malloc(sizeof(int));*a= val * val;return a;	//线程函数的返回值 
}

运行结果如下:

参考链接: C语言——多线程基础(pthread)

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

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

相关文章

Python 将列表数据写入文件(txt, csv,excel)

写入txt文件 def text_save(filename, data):#filename为写入txt文件的路径&#xff0c;data为要写入数据列表. file open(filename,a) for i in range(len(data)): s str(data[i]).replace([,).replace(],)#去除[],这两行按数据不同&#xff0c;可以选择 s s.replace(&quo…

NVS入门(基于ESP-IDF)

主要参考资料&#xff1a; B站Up主 孤独的二进制《ESP32 存储篇 NVS 非易失性存储库》 ESP-IDF开发指南>API参考>非易失性存储: https://docs.espressif.com/projects/esp-idf/zh_CN/v5.1/esp32s3/api-reference/storage/nvs_flash.html 目录 概述NVS使用&#xff08;以W…

一键制作底片效果,让视频复古感倍增!

你是否厌倦了千篇一律的视频效果&#xff0c;想要尝试一些与众不同的视觉体验&#xff1f;是否想要让你的视频散发出一种复古、怀旧的气息&#xff1f;现在&#xff0c;有了我们的底片效果制作工具&#xff0c;这些愿望全部实现 首先第一步&#xff0c;我们要进入视频剪辑高手…

16.Linux基本使用和程序部署

文章目录 1.Linux 背景知识1.1Linux 是什么1.2Linux 发行版1.3关于 Linux 我们学习什么 2.Linux 环境搭建2.1环境搭建方式2.2使用云服务器2.3使用终端软件连接到 Linux2.3.1什么是终端软件2.3.2下载安装 XShell2.3.3使用 XShell 登陆主机 3.Linux 常用命令3.1 ls3.2 pwd3.3 cd3…

关于cdn资源失效的问题,一个月了都解决不了,七牛云技术这么差的吗?

起因 最近登录我的gpt镜像网站后&#xff0c;发现关于面具的图片资源都失效了 CoCo-AI 于是紧急使用 F12 排查原因 发现所有图片拿出来都已经无法访问了。看来是资源出了问题 在网上一番搜索后发现是 cdn.staticfile.org 失效导致的&#xff0c;而该静态资源属于七牛云&#…

大数据开发之Hive(查询、分区表和分桶表、函数)

第 6 章&#xff1a;查询 6.1 基本语法及执行顺序 1、查询语句语法 select_expr, select_expr, ... FROM table_reference [WHERE where_condition] [GROUP BY col_list] [ORDER BY col_list] [CLUSTER BY col_list| [DISTRIBUTE BY col_list] [SORT BY col_list]] [LIMIT n…

htmx 只是另一个 JavaScript 框架吗?老外都吵上了

对 htmx 最常见的批评之一通常来自第一次听说它的人&#xff0c;如下所示&#xff1a; 你抱怨现代前端框架的复杂性&#xff0c;但你的解决方案只是另一个复杂的前端框架。 这是一个很好的反对意见&#xff01;对于你引入到项目中的任何第三方 (3P) 代码&#xff0c;你都有权提…

HarmonyOS 开发基础(八)Row和Column

HarmonyOS 开发基础&#xff08;八&#xff09;Row和Column 一、Column 容器 1、容器说明&#xff1a; 纵向容器主轴方向&#xff1a;从上到下纵向交叉轴方向&#xff1a;从左到右横向 2、容器属性&#xff1a; justifyContent&#xff1a;设置子元素在主轴方向的对齐格式…

实例分割论文精读:Mask R-CNN

1.摘要 本文提出了一种概念简单、灵活、通用的实例分割方法&#xff0c;该方法在有效地检测图像中的物体同时&#xff0c;为每个物体实例生成一个实例分割模板&#xff0c;添加了一个分支&#xff0c;用于预测一个对象遮罩&#xff0c;与现有的分支并行&#xff0c;用于边界框…

零知识证明的最新发展和应用

PrimiHub一款由密码学专家团队打造的开源隐私计算平台&#xff0c;专注于分享数据安全、密码学、联邦学习、同态加密等隐私计算领域的技术和内容。 当企业收集大量客户数据去审查、改进产品和服务以及将数据资产货币化时&#xff0c;他们容易受到网络攻击威胁&#xff0c;造成数…

RC4加解密源码

本文介绍RC4加解密源码。 RC4&#xff08;来自Rivest Cipher 4的缩写&#xff09;是一种流加密算法&#xff0c;密钥长度可变。它加解密使用相同的密钥&#xff0c;因此也属于对称加密算法。RC4具有加解密速度快&#xff0c;算法简单等优点&#xff0c;在算力不高场合&#xf…

昇腾910b部署Chatglm3-6b进行流式输出【pytorch框架】NPU推理

文章目录 准备阶段避坑阶段添加代码结果展示 准备阶段 配套软件包Ascend-cann-toolkit和Ascend-cann-nnae适配昇腾的Pytorch适配昇腾的Torchvision Adapter下载ChatGLM3代码下载chatglm3-6b模型&#xff0c;或在modelscope里下载 避坑阶段 每个人的服务器都不一样&#xff0…

Pixart PAR2861 蓝牙 keyboard 开发笔记

Pixart PAR2861 是一款采用32 bits ARM Cortex-M0 低功耗、高效能 2.4GHz RF 的 SoC。 该 SoC 整合了高效能的 2.4GHz RF 收发器、硬体Keyscan、硬体按键防弹跳、SPI、I2C、PWM LED、ADC、UART等。内建 DC/DC 转换器和 LDO 为独立 HID 应用提供完整的低功耗 SoC 解决方案。 1.…

2023年网络安全事件处罚盘点,文件销毁 硬盘销毁 物料销毁

《中华人民共和国网络安全法》是我国第一部全面规范网络空间安全管理方面问题的基础性法律&#xff0c;是我国网络空间法治建设的重要里程碑&#xff0c;《中华人民共和国网络安全法》从2013年下半年提上日程&#xff0c;到2016年年底颁布&#xff0c;自2017年6月1日起施行&…

滑动登陆注册同页面

这是一个登陆注册在同一个页面滑动选择的页面 技术&#xff1a;html、css、javascript 简单页面实现&#xff08;为了方便&#xff0c;已将代码放在同一文件引用&#xff09;&#xff1a; 1.1、效果图 1.2、完整代码&#xff1a; <!DOCTYPE html> <html lang"…

virtualbox Ubuntu 网络连接

一、网络连接需求1—— 上网&#xff1a; 虚拟机默认的NAT连接方式&#xff0c;几乎不需要怎么配置&#xff0c;即可实现上网。 enp0s17以太网必须要开启&#xff0c;才能上网&#xff1b; 但是主机ping不通虚拟机&#xff0c;貌似可以ping 127.0.0.1; 二、主机和虚拟机相互p…

语境化语言表示模型-ELMO、BERT、GPT、XLnet

一.语境化语言表示模型介绍 语境化语言表示模型&#xff08;Contextualized Language Representation Models&#xff09;是一类在自然语言处理领域中取得显著成功的模型&#xff0c;其主要特点是能够根据上下文动态地学习词汇和短语的表示。这些模型利用了上下文信息&#xf…

DrGraph原理示教 - OpenCV 4 功能 - 形态操作

形态类型 从OpenCV图像处理基本知识来看&#xff0c;膨胀腐蚀操作后&#xff0c;还有形态操作&#xff0c;如开运算、闭运算、梯度、礼帽与黑帽&#xff0c;感觉很多&#xff0c;其实&#xff0c;本质上就是批处理操作&#xff0c;如 开运算&#xff1a;先腐蚀&#xff0c;再膨…

大模型LLM Agent在 Text2SQL 应用上的实践

1.前言 在上篇文章中「如何通过Prompt优化Text2SQL的效果」介绍了基于Prompt Engineering来优化Text2SQL效果的实践&#xff0c;除此之外我们还可以使用Agent来优化大模型应用的效果。 本文将从以下4个方面探讨通过AI Agent来优化LLM的Text2SQL转换效果。 1 Agent概述2 Lang…

肯尼斯·里科《C和指针》第6章 指针(3)

肯尼斯里科《C和指针》第6章 指针&#xff08;1&#xff09;-CSDN博客 肯尼斯里科《C和指针》第6章 指针&#xff08;2&#xff09;-CSDN博客 前置知识&#xff1a;左值右值 为了理解有些操作符存在的限制&#xff0c;必须理解左值(L-value)和右值(R-value)之间的区别。这两个…