【Operating Systems:Three Easy Pieces 操作系统导论 】第28章 插叙:线程 API

本文主要是介绍【Operating Systems:Three Easy Pieces 操作系统导论 】第28章 插叙:线程 API,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【Operating Systems:Three Easy Pieces 操作系统导论 】
在这里插入图片描述

第28章 插叙:线程 API

pthread 库介绍

线程创建

#include <pthread.h> // 头文件 
int
pthread_create(pthread_t * thread,const pthread_attr_t * attr,void * (*start_routine)(void*),void * arg
);
  • thread 指向 pthread_t 结构类型的指针,我们将利用这个结构与该线程交互,因此需要将它传入 pthread_create(),以便将它初始化。相当于该线程的身份证
  • attr 指定该线程可能具有的任何属性。包括设置栈大小,或关于该线程调度优先级的信息等
  • *start_routine 一个函数指针(function pointer),指向要运行的函数
  • arg要运行的函数的参数

线程完成

通过pthread_join阻塞等待线程完成

pthread_create(&p, NULL, mythread, (void *) 100);  // 通常创建 传入NULL就可以  eg 对于一个int将他打包为参数 不需要
pthread_join(p, (void **) &m);   // 第一个参数是pthread_t 类型  第二个参数是 指针类型   如果不需要返回值 也可以传null

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
// 或是int rc = pthread_mutex_init(&lock, NULL);
pthread_mutex_lock(&lock);
x = x + 1; // or whatever your critical section is
pthread_mutex_unlock(&lock);

创建一个临界区
如果另一个线程确实持有该锁,那么尝试获取该锁的线程将不会从该调用返回(阻塞等待),直到获得该锁

int pthread_mutex_trylock (pthread_mutex_t *mutex);
int pthread_mutex_timedlock (pthread_mutex_t *mutex, struct timespec *abs_timeout); // 避免卡在无期限的获取锁ing

这两个调用用于获取锁(非阻塞获取锁)。如果锁已被占用,则 trylock 版本将失败。获取锁的 timedlock 定版本会在超时或获取锁后返回,以先发生者为准。通常应避免使用这两种版本

条件变量(Condition Variables)

不同于信号量(semaphore),信号量应该是条件变量+互斥锁的组合,见此文
当线程之间必须发生某种信号时,如果一个线程在等待另一个线程继续执行某些操作,条件变量就很有用。

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_signal(pthread_cond_t *cond);

要使用条件变量,必须另外有一个与此条件相关的锁。在调用上述任何一个函数时,应该持有这个锁。
第一个函数pthread_cond_wait()使调用线程进入休眠状态,因此等待其他线程发出信号,通常当程序中的某些内容发生变化时,现在正在休眠的线程可能会关心它。典型的用法如下所示:

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_lock(&lock);
while (ready == 0)pthread_cond_wait(&cond, &lock);
pthread_mutex_unlock(&lock);

唤醒线程的代码运行在另外某个线程中,调用pthread_cond_signal时也需要持有对应锁。像下面这样:

pthread_mutex_lock(&lock);
ready = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);

pthread_cond_wait有第二个参数,因为它会隐式地释放锁,以便在其线程休眠后唤醒线程可以获取锁,之后又会重新获得锁。
本例通过 while 判断 ready 的值的变更,而不是通过条件变量唤醒判断 ready 已变更。将唤醒视为某种事物可能已经发生变化的暗示,而不是绝对的事实,这样更安全

编译和运行

只要main.c 包含 pthread.h 你就成功编译了一个并发程序 。链接时需要 pthread 库,增加 -pthread 标记。

prompt> gcc -o main main.c -Wall -pthread

小结

补充:线程 API 指导
当你使用 POSIX 线程库(或者实际上,任何线程库)来构建多线程程序时,需要记住一些小而重 要的事情:

  • 保持简洁。最重要的一点,线程之间的锁和信号的代码应该尽可能简洁。复杂的线程交互容易产生缺陷。
  • 让线程交互减到最少。尽量减少线程之间的交互。每次交互都应该想清楚,并用验证过的、正确的方法来实现(很多方法会在后续章节中学习)。
  • 初始化锁和条件变量。未初始化的代码有时工作正常,有时失败,会产生奇怪的结果。
  • 检查返回值。当然,任何 C 和 UNIX 的程序,都应该检查返回值,这里也是一样。否则会导致古怪而难以理解的行为,让你尖叫,或者痛苦地揪自己的头发。
  • 注意传给线程的参数和返回值。具体来说,如果传递在栈上分配的变量的引用,可能就是在犯错误。
  • 每个线程都有自己的栈。类似于上一条,记住每一个线程都有自己的栈。因此,线程局部变量应该是线程私有的,其他线程不应该访问。线程之间共享数据,值要在堆(heap)或者其他全局可访问的位置。
  • 线程之间总是通过条件变量发送信号。切记不要用标记变量来同步。
  • 多查手册。尤其是 Linux 的 pthread 手册,有更多的细节、更丰富的内容。请仔细阅读!

这篇关于【Operating Systems:Three Easy Pieces 操作系统导论 】第28章 插叙:线程 API的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

Spring Boot3虚拟线程的使用步骤详解

《SpringBoot3虚拟线程的使用步骤详解》虚拟线程是Java19中引入的一个新特性,旨在通过简化线程管理来提升应用程序的并发性能,:本文主要介绍SpringBoot3虚拟线程的使用步骤,... 目录问题根源分析解决方案验证验证实验实验1:未启用keep-alive实验2:启用keep-alive扩展建

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Java终止正在运行的线程的三种方法

《Java终止正在运行的线程的三种方法》停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作,停止一个线程可以用Thread.stop()方法,但最好不要用它,本文给大家介绍了... 目录前言1. 停止不了的线程2. 判断线程是否停止状态3. 能停止的线程–异常法4. 在沉睡中停止5

Java捕获ThreadPoolExecutor内部线程异常的四种方法

《Java捕获ThreadPoolExecutor内部线程异常的四种方法》这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感... 目录方案 1方案 2方案 3方案 4结论方案 1使用 execute + try-catch 记录

SpringBoot集成图片验证码框架easy-captcha的详细过程

《SpringBoot集成图片验证码框架easy-captcha的详细过程》本文介绍了如何将Easy-Captcha框架集成到SpringBoot项目中,实现图片验证码功能,Easy-Captcha是... 目录SpringBoot集成图片验证码框架easy-captcha一、引言二、依赖三、代码1. Ea

C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)

《C#集成DeepSeek模型实现AI私有化的流程步骤(本地部署与API调用教程)》本文主要介绍了C#集成DeepSeek模型实现AI私有化的方法,包括搭建基础环境,如安装Ollama和下载DeepS... 目录前言搭建基础环境1、安装 Ollama2、下载 DeepSeek R1 模型客户端 ChatBo

Spring Boot 中正确地在异步线程中使用 HttpServletRequest的方法

《SpringBoot中正确地在异步线程中使用HttpServletRequest的方法》文章讨论了在SpringBoot中如何在异步线程中正确使用HttpServletRequest的问题,... 目录前言一、问题的来源:为什么异步线程中无法访问 HttpServletRequest?1. 请求上下文与线

在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

《在SpringBoot中使用异步线程时的HttpServletRequest复用问题记录》文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致... 目录一、问题描述:异步线程操作导致请求复用时 Cookie 解析失败1. 场景背景2. 问题根源二、问题详细分

SpringBoot整合easy-es的详细过程

《SpringBoot整合easy-es的详细过程》本文介绍了EasyES,一个基于Elasticsearch的ORM框架,旨在简化开发流程并提高效率,EasyES支持SpringBoot框架,并提供... 目录一、easy-es简介二、实现基于Spring Boot框架的应用程序代码1.添加相关依赖2.添

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.