Linux多线程编程

2023-05-16

       在传统的UNIX模型中,当一个进程需要另一个实体来完成某事,它就fork一个子进程并让子进程去处理。但是fork的调用有如下缺点:

      1fork代价是 昂贵的fork要把父进程的内存印象复制到子进程,并在子进程中复制所有描述符等。

      2fork返回之后父子进程之间信息的传递需要进程通信机制。调用fork之前父进程向尚未存在的子进程传递信息相当容易,因为子进程将从父进程数据空间及所有描述符的一个副本开始运行,但是从子进程向父进程返回信息却比较费力。

      针对这两点,多线程技术相应而生,它具有如下优越性:

      1)它是一种非常"节俭"的多任务操作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。

      2)线程间方便的通信更加方便。由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。但是,同一进程内的所有线程共享相同的全局内存,这样线程之间的通信就变得相当简单,随之而来的就是同步问题

一、基本线程函数

1.pthread_create函数,创建线程

int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*func)(void *), void *arg);

      pthread_t *tid:一个进程内的各个线程是由线程ID标识的,如果新线程创建成功,返回tid指针

      const pthread_attr_t *attr:每个线程有多个属性,包括优先级、初始栈大小、是否是一个守护线程等等。

      void *(*func)(void *)线程启动函数,线程从调用这个函数开始,或显示结束(调用pthread_exit()),或隐式结束(让该函数返回)。

      void *arg:线程执行func函数的传递参数

2.pthread_join函数,等待一个线程终止

int pthread_join(pthread_t *tid, void **status);

      void **status:二级指针,如果status指针非空,那么所等待线程的返回值将存放在status指向的位置。

3.pthread_self函数,返回线程ID

int pthread_self(void);

      跟进程比较,相当于getpid

4.pthread_detach函数,线程分离

int pthread_detach(pthread_t tid);  

       线程或者是可汇合的joinable),或者是脱离的detach)。当可汇合的线程终止时,线程ID和退出状态将保留,知道另外一个线程调用pthread_join。脱离的线程终止时,释放所有的资源,因此我们不能等待它终止。若要一个线程知道另一个线程的终止时间,我们就要保留第二个线程的可汇合性。

5.pthread_exit函数,线程终止

int pthread_detach(pthread_t tid);  

      若线程未脱离,那么它的线程ID和退出状态将保留到另外一个线程调用pthread_join为止。

二、多线程的同步

      有了上面的基本函数还不足以完成本题的要求,为什么呢?因为题目要求按照ABCABC...的方式打印,而3个线程却在抢占资源,所以无法控制排列顺序。这时就需要用到多线程编程中的同步技术。

      对于多线程编程来说,同步就是同一时间只允许一个线程访问资源,而其他线程不能访问。多线程有3种同步方式:

  • 互斥锁
  • 条件变量
  • 读写锁

2.1 互斥锁

      互斥锁是最基本的同步方式,它用来保护一个临界区,保证任何时刻只由一个线程在执行其中的代码。这个临界区通常是线程的共享数据

      下面三个函数给一个互斥锁上锁和解锁:


int pthread_mutex_lock(pthread_mutex_t *mptr);

int pthread_mutex_trylock(pthread_mutex_t *mptr);

int pthread_mutex_unlock(pthread_mutex_t *mptr);

 

  假设线程2要给已经被线程1锁住的互斥锁(mutex)上锁(即执行pthread_mutex_lock(mutex)),那么它将一直阻塞直到到线程1解锁为止(即释放mutex)。

      如果互斥锁变量时静态分配的,通常初始化为常值PTHREAD_MUTEX_INITIALIZER,如果互斥锁是动态分配的,那么在运行时调用pthread_mutex_init函数来初始化。

2.2 条件变量

      互斥锁用于上锁,而条件变量则用于等待,通常它都会跟互斥锁一起使用。


int pthread_cond_wait(pthread_cond_t *cptr,pthread_mutex_t *mptr);

int pthread_cond_signal(pthread_cond_t *cptr);

 通常pthread_cond_signal只唤醒等待在相应条件变量上的一个线程,若有多个线程需要被唤醒呢,这就要使用下面的函数了:

int pthread_cond_broadcast(pthread_cond_t *cptr);

2.3 读写锁

      互斥锁将试图进入连你姐去的其他简称阻塞住,而读写锁是将读和写作了区分,读写锁的分配规则如下:

      1)只要没有线程持有某个给定的读写锁用于写,那么任意数目的线程可以持有该读写锁用于读;

      2)仅当没有线程持有某个给定的读写锁用于读或用于写时,才能分配该读写锁用于写。

int pthread_rwlock_rdlock(pthread_relock_t *rwptr);

int pthread_rwlock_wrlock(pthread_relock_t *rwptr);

int pthread_rwlock_unlock(pthread_relock_t *rwptr);

三、多线程问题分析

   分析此题:

  1.主线程main创建3个线程tid0tid1tid2

  2.设一个全局变量num,互斥锁mutex保护此临界区保证每次只有一个线程访问num

  3.若抢占到资源的线程tid并不是我们需要的,那么让它阻塞;

  4.若抢占到资源的线程tid正好是我们需要的,那么就打印相应字母;

  5.解锁,唤醒其他两个等待线程;

  6.main函数等待3个线程打印结束才结束。

      代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<error.h>
#include<unistd.h>
#include<pthread.h>
 
int num=0;
 
static pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
 
void *func(void *);
 
int main()
{
    pthread_t tid[3];
    int ret=0,i;
    for(i=0;i<3;i++)
        if((ret=pthread_create(&tid[i],NULL,func,(void*)i))!=0)
            printf("create thread_%c error\n",i+'A');
    for(i=0;i<3;i++)
        pthread_join(tid[i],NULL);
    printf("\n");
    return 0;
}
 
void *func(void *argc)
{
    int i;
    for(i=0;i<10;i++)
    {
        pthread_mutex_lock(&mutex);
        while(num!=(int)argc)
            pthread_cond_wait(&cond,&mutex);  //收到条件变量,则继续执行循环
        printf("%c",num+'A');
        num=(num+1)%3;
        pthread_mutex_unlock(&mutex);
        pthread_cond_broadcast(&cond);
    }
    pthread_exit(0);
}

四、死锁问题

       死锁是指两个或两个以上的执行序在执行过程中, 因争夺资源而造成的一种互相等待的现象。例如: 一个线程 T1 已锁定了一个资源 R1, 又想去锁定资源 R2,而此时另一个线程 T2 已锁定了资源 R2,却想去锁定资源R1,两个线程都想得到对方的资源,而不愿释放自己的资源,造成两个线程都在等待,而无法执行的情况,如下图所示。

https://img-blog.csdn.net/20180531224921372

                                                                               图4-1 死锁示意图

 

参考:http://www.cnblogs.com/Rosanna/p/3576715.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux多线程编程 的相关文章

  • VINS-Mono 论文解读(IMU预积分残差+Marg边缘化)

    目录 VIO引出原因 xff1a 融合方案 xff1a 本文贡献 xff1a 0 总体框架 0 1 数据预处理 xff08 IMU预积分见标题1 xff09 0 2 初始化 A 滑动窗口 Sliding Window 纯视觉SfM B 视觉
  • 牛客网C++刷题要点

    1 虚函数 不要在构造函数和析构函数中调用虚函数 下面说说原理 xff1a 假如基类有个虚函数 那么编译器会为其创建虚函数表vtbl 并在对象的内存空间创建虚函数指针vptr 虚函数表的原理是每个类会在里面有自己的所能调用到的虚函数地址 对
  • 3D检测入门 - KITTI数据集

    参考链接 官网 xff1a http www cvlibs net datasets kitti index php 传感器介绍 xff1a http www cvlibs net datasets kitti setup php 相机内外
  • 请多多指教

    我是菜鸟 xff0c 还请各位大虾多多指教 xff01
  • VINS-DUAL 测试(小觅相机)

    设置小觅相机参数 直接从小觅相机内部获取各种参数 xff0c 把小觅相机给的SDK编译好后 xff0c 找到以下路径中生成的可执行文件 MYNT EYE D SDK samples output bin 直接执行下面两个文件 xff1a g
  • VINS-FUSION 研究日志 (3)进入 estimator.cpp Part A

    继续碎碎念梳理VINS FUSION 上一篇博文梳理了整个程序的入口 xff0c 其实只是做了传感器参数的读取与配置 xff0c 传感器测量数据的订阅 两件事情 estimator cpp 中有一个持续运行的线程 xff0c 是在 void
  • “Failed to get convolution algorithm. This is probably because cuDNN failed to initialize”错误的解决办法

    最近在使用TF2 0 运行程序出现以下错误 Failed to get convolution algorithm This is probably because cuDNN failed to initialize 一开始怀疑是CUDA
  • Linux多线程调用ubus导致死锁问题

    测试组发现用户进程在某种特定情况下 xff0c 会出现死锁 xff0c 现象是进程还在S状态 xff0c 但没有任何反应 xff0c 所以怀疑死锁 问题复现 通过几次测试发现 xff0c 进程中设置的参数恢复出厂后重启进程很大概率会出现死锁
  • Hi3559AV100 HDMI转MIPI-CSI LT6911UXC转换芯片调试

    Hi3559AV100项目 xff0c 需要接HDMI 4K摄像头 xff0c 需要把HDMI转成MIPI CSI信号接入CPU xff0c 从而实现信号的转换和实现 我们拿到的海思开发板是HI3559A4SDMEB VER A xff0c
  • 电脑抓wifi空中包三种方法

    WIN10电脑 下载wireshark软件 xff0c 设置WIFI网卡为monitor模式 xff1a C WINDOWS system32 gt cd Npcap C Windows System32 Npcap gt WlanHelp
  • 简述TCP的三次握手过程

    TCP握手协议 在TCP IP协议中 TCP协议提供可靠的连接服务 采用三次握手建立一个连接 第一次握手 xff1a 建立连接时 客户端发送syn包 syn 61 j 到服务器 并进入SYN SEND状态 等待服务器确认 xff1b SYN
  • buildroot使用外部编译链编译bluez蓝牙工具

    在开发ublox w263 wifi蓝牙时 xff0c 之前是使用yocto系统集成编译出的bluez工具 xff0c 减少了自己编译工具软件和依赖库的工作 xff0c 切换项目使用原生linux系统后 xff0c 所以的软件需要自己编译
  • 软件替代硬件HW_RANDOM随机数解决方案

    问题背景 使用低成本平台方案时 xff0c 发现不支持HW RANDOM硬件随机数 xff0c 这样在开启wifi wpa2加密ap后 xff0c 电脑多次提示连接失败才连接成功 xff0c 很影响用户体验 硬件不支持硬件随机数那么就需要使
  • Android下打印出现read: Unexpected EOF!分析

    背景 xff1a 在抓SmePlayer打印时 xff0c 打开debug级别后 xff0c xshell终端就嘟嘟响然后打印出几百行后就打出read Unexpected EOF 结束了 这时候完全没有抓到我需要的打印 xff0c 用lo
  • VMWare中处理器和内存配置含义

    背景 在创建虚拟机系统后 xff0c 默认处理器配置都是为1 xff0c 内存一般选为1G xff0c 然而在使用Linux系统编译大型软件时 xff0c 速度慢耗时较长 xff0c 这时候就需要调整一下处理器和内存配置 xff0c 使得计
  • Linux mkfs.ext4命令参数使用

    命令使用 mkfs ext4 参数 设备 参数说明 c 格式化前检查分区是否有坏块 Checking for bad blocks read only test 19 34 done 0 21 elapsed 0 0 0 errors Ch
  • Xshell 6多个会话窗口消失只能显示一个问题解决

    背景 某一天同事操作了我的Xshell导致我的会话窗口消失只能显示一个 xff0c 通过点击选项卡排列可以显示出消失的窗口 xff0c 但是使用极为不方便 xff0c 下面问题解决 解决 正常显示 xff1a 有三个选项窗口 异常显示 xf
  • OpenWrt学习(一)搭建Linux开发环境

    环境 目前大部分的 linux开发都是在PC虚拟机上进行的 xff0c 所采用的 linux系统版本有 Ubuntu Redhat Debian Fedora 等 xff0c 我们一般在 windows 操作系统上利用 VMware 43
  • OpenWrt学习(三)源码大包编译

    编译大包 make V 61 99 xff0c V 61 99 用来生成编译过程的详细信息 xff0c 方便查找出错原因 xff0c 或者用V 61 s 建议加 j x xff08 x 为CPU core数量 xff09 选项 xff0c
  • Linux gcc自带检测内存泄漏工具asan

    背景 排查和检测内存泄漏的问题时 xff0c 需要选择一些好用的工具 xff0c 由于dmalloc编译复杂 xff0c valgrind依赖太多 xff0c 所以选择使用gcc自带检测内存泄漏工具asan xff0c 版本4 8之后就支持

随机推荐

  • Linux物理内存较少导致OOM问题分析

    背景 开发项目过程中 xff0c 发现盒子启动后物理内存持续的减少 xff0c CMA内存过了一段时间后也出现明显减少情况 xff0c 到最后会低概率性的出现OOM杀掉进程的情况 xff1b 通过ps命令监控所有进程在开机后的虚拟内存VSZ
  • BaseService --- service层的抽取

    service层的抽取和dao层的抽取差不多相同 xff0c 主要不同点是dao实例化的问题 xff0c 需要在调用时传入 xff0c 并在BaseServiceImpl接收 详细的过程说明请参考dao层的抽取 dao层的抽取 xff1a
  • 数据分析思维之用户标签

    文章目录 1 什么是标签 xff1f 2 用户标签有什么用 xff1f 3 用户标签的制作流程4 用户标签的4大常见问题4 1 没有目标 xff0c 盲目打标4 2 不区分时间状态4 3 行为动机乱归因4 4 结果缺少检验 1 什么是标签
  • 看你能坚持读几本书?!——三十本互联网必看书籍

    写在前面 一直想整理个书单 xff0c 譬如关于EA 企业架构 ABCD 人工智能 大数据 云计算 设备 逻辑 思维 沟通 影响力 领导力 管理 绩效 胜任力 战略 商业方面的书单 xff0c 这里看到了一篇整理的比较好的书单 经过简单编辑
  • Docker学习之安装docker-compose命令(采用Python-pip命令安装)

    Docker学习之安装docker compose命令 采用Python pip命令安装 本机系统环境介绍Docker Compose简介使用Python pip命令进行安装第一步 环境检查第二步 安装Python pip第三步 安装doc
  • ros 下面如何通过vrpn 连接 Optitrack

    tracking system 可以实时的计算出来regid body 的pose xff0c 如何在ros 下面得到 这个pose 呢 xff1f 首先 编译安装 vrpn 然后的话需要配置两台电脑的IP 使他们能够 互相 ping 通
  • kalman滤波器各项参数及矩阵的设置

    参考博客 xff1a https blog csdn net baimafujinji article details 50646814 简单来说 xff0c 卡尔曼滤波器的实现是一个迭代过程 xff0c 使用上一次的结果预测当前的值 xf
  • python_tweets.json (python数据挖掘入门与实践数据集下载)

    最近在看python数据挖掘入门与实践一书 xff0c 书不错 xff0c 有个不好的地方是 xff0c 书上所用的数据集 xff0c 有几个测试数据在网上非常不好找 下面几个资源是我自己整理出来的 xff0c 上传到CSDN xff0c
  • ubuntu20.04_ROS中运行gazebo控制机器人模型报错

    1 无法启动类型为 controller manager spawner 的节点 xff1a controller manager ERROR cannot launch node of type controller manager sp
  • Fast Planner——代码解读参考资料整理

    1 地图部分 1 1 EGO Swarm代码解读 地图部分 参数解读 主要函数解读 1 2 EGO Swarm代码阅读笔记之GridMap类 1 3 EGO PLANNER代码阅读 xff08 地图部分 xff09 1 4 欧几里得距离转换
  • FreeRTOS 10.4.3在RISCV(T-HEAD C906)平台上移植过程

    好记性不如烂笔头 记录点滴移植经历 一方面便于总结提炼 二是分享 让别人少走有些弯路 自己以后踩坑了也爬的利索点 首先梳理一下移植框架 FreeRTOS还是非常简单的 体量上要比RT Thread Nuttx等偏重型的系统轻量不少 这可能也
  • Web服务器CGI的配置

    Web服务器CGI的配置 CGI程序运行在Web服务器端 xff0c Web服务器可以是Apache Nginx等 GGI程序可以是Python Ruby Perl Shell C C 43 43 等 配置 apache默认加载cgi模块
  • 解决mac安装homebrew后报错-bash: brew: command not found

    参照官网上很简单的一句安装命令 xff0c usr bin ruby e 34 curl fsSL https raw githubusercontent com Homebrew install master install 34 安装完
  • 转行的辛苦

    我是2004年毕业的 xff0c 学的专业是市场营销 xff0c 毕业后来到深圳 xff0c 换了很多工作 xff0c 一直都无法找到令自己满意的工作 因为我非常喜欢计算机 xff0c 从中学到大学 xff0c 一直是班级里公认的计算机高手
  • 物联网之轻量级TCP/IP协议栈——Lwip

    简介 Lwip为轻量级的Tcp IP协议栈 xff0c 对于嵌入式设备资源比较友好 xff0c 占用RAM低 xff0c 基本上物联网wifi芯片都会集成此协议栈到SDK中 xff0c 其位于OSI的网路层往上 熟悉socket编程的能够很
  • github下载慢或报错“The-remote-end-hung-up-unexpectedly”解决办法

    github下载慢或报错 The remote end hung up unexpectedly 解决办法 xff1a 该问题往往因为内部网络限制等因素导致 因细节更新 xff0c 欢迎访问本文源站链接 xff1a https turboc
  • git 如何把单个文件回退到某一版本

    git 如何把单个文件回退到某一版本 概要四条命令git restoregit resetgit checkoutgit cherry pick 概要 应用场景 xff1a 在进行一次完整的提交后 xff0c 你可能有有这样的需求 xff1
  • Docker

    学习笔记 一 Docker概述 1 基本介绍 Docker是一个开源的应用容器引擎 xff0c 基于Go语言 xff0c 并遵从apache2 0协议开源 docker可以让开发者打包他们的应用以及依赖包到一个轻量级 可移植的容器中 xff
  • roslaunch 时出现resource 找不到的问题

    Resource not found roslaunch ROS path 0 61 opt ros noetic share ros ROS path 1 61 opt ros noetic share The traceback for
  • Linux多线程编程

    在传统的 UNIX 模型中 xff0c 当一个进程需要另一个实体来完成某事 xff0c 它就 fork 一个子进程并让子进程去处理 但是 fork 的调用有如下缺点 xff1a xff08 1 xff09 fork 的 代价是 昂贵的 fo