Linux 多线程编程

韦东山的例程

所谓线程,就是操作系统所能调度的最小单位。普通的进程,只有一个线程在执行对应的逻辑。我们可以通过多线程编程,使一个进程可以去执行多个不同的任务。相比多进程编程而言,线程享有共享资源,即在进程中出现的全局变量,每个线程都可以去访问它,与进程共享内存空间,使得系统资源消耗减少。

创建线程,使用 pthread_create 函数

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

该函数第一个参数为 pthread_t 指针,用来保存新建线程的线程号

  • 第二个参数表示了线程的属性,一般传入 NULL 表示默认属性
  • 第三个参数是一个函数指针,就是线程执行的函数。这个函数返回值为 void*,形参为void*
  • 第四个参数则表示为向线程处理函数传入的参数,若不传入,可用 NULL 填充


第一个例程:
创线程

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>static void *my_thread_func (void *data)
{while (1){sleep(1);}
}int main(int argc, char **argv)
{pthread_t tid;int ret;/* 1. 创建"接收线程" *///my_thread_func将在线程创建时运行ret = pthread_create(&tid, NULL, my_thread_func, NULL);if (ret){printf("pthread_create err!\n");return -1;}/* 2. 主线程读取标准输入, 发给"接收线程" */while (1){sleep(1);}return 0;
}

编译报错则 加 -lpthread 链接别的库

运行后查看进程 ps 查看线程 ps -T

第二个例程:
目的是创建一个接收线程,这个接收线程能接收主线程给的数据,主线程从标准输入得到数据

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>static char g_buf[1000];
//线程可以访问全局变量,加个标记位
static int g_hasData = 0;
static void *my_thread_func (void *data)
{while (1){//sleep(1);/* 等待通知 */while (g_hasData == 0);/* 打印 */printf("recv: %s\n", g_buf);g_hasData = 0;}return NULL;
}int main(int argc, char **argv)
{pthread_t tid;int ret;/* 1. 创建"接收线程" */ret = pthread_create(&tid, NULL, my_thread_func, NULL);if (ret){printf("pthread_create err!\n");return -1;}/* 2. 主线程读取标准输入, 发给"接收线程" */while (1){fgets(g_buf, 1000, stdin);/* 通知接收线程 */g_hasData = 1;}return 0;
}

但是,这样的代码使得cpu资源消耗很大,fgets用于接收,未发送数据时,它就会处于休眠状态,然而 while(g_hasData == 0) 一直在运行,我们应该考虑让他修眠

///
第三个例程:
应该让主函数收到信号量再去唤醒接收线程

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>static char g_buf[1000];
static sem_t g_sem;
static void *my_thread_func (void *data)
{while (1){//sleep(1);/* 等待通知 *///while (g_hasData == 0);sem_wait(&g_sem);/* 打印 */printf("recv: %s\n", g_buf);}return NULL;
}int main(int argc, char **argv)
{pthread_t tid;int ret;sem_init(&g_sem, 0, 0);/* 1. 创建"接收线程" */ret = pthread_create(&tid, NULL, my_thread_func, NULL);if (ret){printf("pthread_create err!\n");return -1;}/* 2. 主线程读取标准输入, 发给"接收线程" */while (1){fgets(g_buf, 1000, stdin);/* 通知接收线程 */sem_post(&g_sem);}return 0;
}

这样cpu占用高解决了
但是,接收线程在打印g_buf的时候,主线程也是在运行的,那么,接收线程在打印g_buf的时候如果输入了字符串,可能接收线程打印出来的可能半截老数据,半截新数据

/

第四个例程:
我们引入互斥量mutex
第一次代码,主线程接受没问题,子线程无法执行,无法打印
原因是主线程解锁后,可能立马又进入while,这个时候sem_post(&g_sem)却还没有到达子线程!
互斥量总是被主线程获得,子线程没那么快反应,无法获取互斥量

while (1){pthread_mutex_lock(&g_tMutex);fgets(buf, 1000, stdin);pthread_mutex_unlock(&g_tMutex);/* 通知接收线程 */sem_post(&g_sem);}

主线程获得互斥量时间太长,我们想办法让他短一点
读数据读临时buf,得到数据后拷入g_buf中去!
这样,主线程占用互斥锁的时间主要就是数据拷贝和设置g_hasData变量的时间,相比之前直接在获取互斥锁的情况下读取到g_buf,减少了在互斥锁保护下的fgets操作时间(fgets可能会因为等待用户输入而长时间占用互斥锁),所以先输完再说,加大子线程运行几率

while (1){fgets(buf, 1000, stdin);pthread_mutex_lock(&g_tMutex);memcpy(g_buf, buf, 1000);pthread_mutex_unlock(&g_tMutex);/* 通知接收线程 */sem_post(&g_sem);}

这是完整代码

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>static char g_buf[1000];
static sem_t g_sem;
//定义互斥量
static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;static void *my_thread_func (void *data)
{while (1){//sleep(1);/* 等待通知 *///while (g_hasData == 0);sem_wait(&g_sem);/* 打印 */pthread_mutex_lock(&g_tMutex);printf("recv: %s\n", g_buf);pthread_mutex_unlock(&g_tMutex);}return NULL;
}int main(int argc, char **argv)
{pthread_t tid;int ret;char buf[1000];sem_init(&g_sem, 0, 0);/* 1. 创建"接收线程" */ret = pthread_create(&tid, NULL, my_thread_func, NULL);if (ret){printf("pthread_create err!\n");return -1;}/* 2. 主线程读取标准输入, 发给"接收线程" */while (1){fgets(buf, 1000, stdin);pthread_mutex_lock(&g_tMutex);memcpy(g_buf, buf, 1000);pthread_mutex_unlock(&g_tMutex);/* 通知接收线程 */sem_post(&g_sem);}return 0;
}

第五个例程:

同步操作之条件变量

和互斥量同时使用
在这里插入图片描述

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>static char g_buf[1000];
static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  g_tConVar = PTHREAD_COND_INITIALIZER;static void *my_thread_func (void *data)
{while (1){//sleep(1);/* 等待通知 *///while (g_hasData == 0);pthread_mutex_lock(&g_tMutex);pthread_cond_wait(&g_tConVar, &g_tMutex);	/* 打印 */printf("recv: %s\n", g_buf);pthread_mutex_unlock(&g_tMutex);}return NULL;
}int main(int argc, char **argv)
{pthread_t tid;int ret;char buf[1000];/* 1. 创建"接收线程" */ret = pthread_create(&tid, NULL, my_thread_func, NULL);if (ret){printf("pthread_create err!\n");return -1;}/* 2. 主线程读取标准输入, 发给"接收线程" */while (1){fgets(buf, 1000, stdin);pthread_mutex_lock(&g_tMutex);memcpy(g_buf, buf, 1000);pthread_cond_signal(&g_tConVar); /* 通知接收线程 */pthread_mutex_unlock(&g_tMutex);}return 0;
}

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

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

相关文章

后端:Spring-1

文章目录 1. 了解 spring(Spring Framework)2. 基于maven搭建Spring框架2.1 纯xml配置方式来实现Spring2.2 注解方式来实现Spring3. Java Config类来实现Spring 2.4 总结 1. 了解 spring(Spring Framework) 传统方式构建spring(指的是Spring Framework)项目&#xff0c;导入依…

【C++动态规划 01背包】2787. 将一个数字表示成幂的和的方案数

本文涉及知识点 C动态规划 C背包问题 LeetCode2787. 将一个数字表示成幂的和的方案数 给你两个 正 整数 n 和 x 。 请你返回将 n 表示成一些 互不相同 正整数的 x 次幂之和的方案数。换句话说&#xff0c;你需要返回互不相同整数 [n1, n2, …, nk] 的集合数目&#xff0c;满…

Python爬虫的京东大冒险:如何高效获取商品详情的秘籍

在这个由代码编织的电商世界里&#xff0c;京东商品详情就像是被锁在高塔中的公主&#xff0c;等待着勇敢的Python爬虫骑士去解救。今天&#xff0c;我们要讲述的是如何成为一名Python爬虫骑士&#xff0c;携带你的代码长矛&#xff0c;穿梭在API的数据森林中&#xff0c;高效获…

SpringBoot【实用篇】- 测试

文章目录 目标&#xff1a;1.加载测试专用属性3.Web环境模拟测试2.加载测试专用配置4.数据层测试回滚5.测试用例数据设定 目标&#xff1a; 加载测试专用属性加载测试专用配置Web环境模拟测试数据层测试回滚测试用例数据设定 1.加载测试专用属性 我们在前面讲配置高级的时候…

vfx特效有多烧钱?云渲染农场减少vfx特效成本

特效制作一直是电影制作中的烧钱大户&#xff0c;尤其是视觉特效&#xff08;VFX&#xff09;的高昂成本让许多项目望而却步。但随着云渲染农场技术的发展&#xff0c;VFX特效的成本得到了有效控制&#xff0c;为电影工业带来了革命性的变化。 在电影工业中&#xff0c;VFX特效…

任何python安装gdal出现的问题

Releases cgohlke/geospatial-wheels GitHubGeospatial library wheels for Python on Windows. Contribute to cgohlke/geospatial-wheels development by creating an account on GitHub.https://github.com/cgohlke/geospatial-wheels/releases 各种乱七八糟的gdal库问题…

tensorflow案例4--人脸识别(损失函数选取,调用VGG16模型以及改进写法)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 这个模型结构算上之前的pytorch版本的&#xff0c;算是花了不少时间&#xff0c;但是效果一直没有达到理想情况&#xff0c;主要是验证集和训练集准确率…

SPA和SSR

单页面应用程序(SPA) 单页面应用(SPA)全称是:Single-page application, SPA应用是在客户端呈现的(术语称:CRS)。 SPA应用默认只返回一个空HTML页面&#xff0c;如:body只有<div id"app"></div>而整个应用程序的内容都是通过JavaScript动态加载&#xf…

【 纷享销客-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

基于SpringBoot和PostGIS的世界各国邻国可视化实践

目录 前言 一、空间数据查询基础 1、空间数据库基础 2、空间相邻查询 二、SpringBoot后台功能设计 1、后台查询接口的实现 2、业务接口设计 三、Leaflet进行WebGIS开发 1、整体结构介绍 2、相邻国家展示可视化 四、成果展示 1、印度及其邻国 2、乌克兰及其邻国 3、…

Python之groupby()及aggregate()方法

目录 数据准备df.describe()思考1 分组 pd.groupby()思考2 df.aggregate()思考1 现在有一份titanic_train.csv&#xff0c;包含泰坦尼克号乘客信息及获救情况的明细数据&#xff0c;我们需要使用一些聚合函数&#xff0c;统计相关指标。 数据准备 import pandas as pd df pd.…

Unity 二次元三渲二

三渲二 注意&#xff1a;Unity必须是2022.3LTS及以上和URP项目&#xff01;&#xff01;&#xff01; 下载三渲二插件 【如何将原神的角色导入Unity】全网最细致教程&#xff0c;全程干货。不使用任何收费插件&#xff0c;使用Spring Bone对头发和衣服进行物理模拟。_原神 步…

Unity计算二维向量夹角余弦值和正弦值的优化方法参考

如果不考虑优化问题&#xff0c;计算两个向量的余弦值或者正弦值可以直接使用类似的方法&#xff1a; [SerializeField] Vector2 v1, v2;void Start() {float valCos Mathf.Acos(Vector2.SignedAngle(v1, v2));float valSin Mathf.Asin(Vector2.SignedAngle(v1, v2)); } 但是…

深度|谁在为OpenAI和Anthropic的AI编程竞赛提供“军火”?已赚得盆满钵满

图片来源&#xff1a;Unsplash AI 开发者之所以一致认为编程的重要性&#xff0c;是有原因的&#xff1a;大型语言模型编程能力越强&#xff0c;它回答与软件无关的其他类型问题的能力也越强。 去年秋天&#xff0c;几位 Google 人工智能领导者与初创公司 CEO Jonathan Siddh…

2024年北京市安全员-A证证模拟考试题库及北京市安全员-A证理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年北京市安全员-A证证模拟考试题库及北京市安全员-A证理论考试试题是由安全生产模拟考试一点通提供&#xff0c;北京市安全员-A证证模拟考试题库是根据北京市安全员-A证最新版教材&#xff0c;北京市安全员-A证大…

[ 问题解决篇 ] win11中本地组策略编辑器gpedit.msc打不开(gpedit.msc缺失)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

前端聊天室页面开发(赛博朋克科技风,内含源码)

肝了一天&#xff0c;经过各种处理美化&#xff0c;肝出来了一个赛博朋克科技风的前端页面&#xff0c;用的原生三件套htmlcssjavascript开发的&#xff0c;本来想是加点功能调用一下gpt接口&#xff0c;但是基本都需要webscoket通信&#xff0c;可惜我js学的不是很深入&#x…

TMDOG的Gin学习笔记_01——初识Gin框架

TMDOG的Gin学习笔记_01——初识Gin框架 博客地址&#xff1a;[TMDOG的博客](https://blog.tmdog114514.icu) 作者自述&#xff1a; 停更太久了&#xff0c;是因为开学了课太多了&#xff0c;并且我一直在准备上篇文章的内容正在coding&#xff0c;就先搁置了更新博客QAQ&…

wsl2.0(windows linux子系统)使用流程

1.什么是wsl wsl指的是windows的linux子系统&#xff0c;最初是wsl1.0&#xff0c;靠windows内核来模拟linux内核&#xff0c;并不运行真正的linux内核&#xff0c;所以有时会有兼容性的问题。 而wsl2.0是基于windows自带的虚拟机功能hyper-v的&#xff0c;它会把设备上的每个…

计算机网络:网络层 —— IPv4 数据报的首部格式

文章目录 IPv4数据报的首部格式IPv4数据报分片生存时间 TTL字段协议字段首部检验和字段 IPv4数据报的首部格式 IPv4 数据报的首部格式及其内容是实现 IPv4 协议各种功能的基础。 在 TCP/IP 标准中&#xff0c;各种数据格式常常以32比特(即4字节)为单位来描述 固定部分&#x…