【Linux-day11-线程的创建与同步】

news2024/11/30 8:37:53

Linux 线程的创建与同步

线程的概念

线程是进程内部的一条执行序列或执行路径,一个进程可以包含多条线程。

进程与线程的区别

  • 进程是资源分配的最小单位,线程是 CPU 调度的最小单位
  • 进程有自己的独立地址空间,线程共享进程中的地址空间
  • 进程的创建消耗资源大,线程的创建相对较小
  • 进程的切换开销大,线程的切换开销相对较小

线程的实现方式

在操作系统中,线程的实现有以下三种方式:

  • 内核级线程
  • 用户级线程
  • 组合级线程

Linux 中线程的实现

Linux 实现线程的机制非常独特。从内核的角度来说,它并没有线程这个概念。Linux 把
所有的线程都当做进程来实现。内核并没有准备特别的调度算法或是定义特别的数据结构来
表征线程。相反,线程仅仅被视为一个与其他进程共享某些资源的进程。每个线程都拥有唯
一隶属于自己的 task_struct,所以在内核中,它看起来就像是一个普通的进程(只是线程和
其他一些进程共享某些资源,如地址空间)。

线程库中的接口介绍

pthread_create()用于创建线程

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

成功返回 0, 失败返回错误码

thread: 接收创建的线程的 ID

attr: 指定线程的属性

start_routine: 指定线程函数

arg: 给线程函数传递的参数

pthread_exit()退出线程

int pthread_exit(void *retval);

pthread_exit()退出线程

retval:指定退出信息

pthread_join()等待 thread 指定的线程退出,线程未退出时,该方法阻塞

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

retval:接收 thread 线程退出时,指定的退出信息

测试代码1

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>

void* fun(void* arg)
{
    int* p = (int*)arg;
    int val = *p;
        printf("%d\n",val);
    return NULL;
}

int main()
{
    pthread_t id[5];
    int i=0;
    for(;i<5;i++)
    {
        pthread_create(&id[i],NULL,fun,(void*)&i);
    }
    for(i=0;i<5;i++)
    {
        pthread_join(id[i],NULL);
    }
    exit(0);
}

预估:会出现0 1 2 3 4按一定顺序

结果如图:

我们发现结果和预想的不一样,这是因为线程是并发运行的,主线程main()和5个副线程都在同时运行,fun是通过指针解引用,主线程会随时改变i的值 ; pthread_create(&id[i],NULL,fun,(void*)&i);只是向内核申请,不一定顺序批准。

测试代码2

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
int val = 0;
void* fun(void* arg)
{
    for(int i=0;i<1000;i++)
    {
        printf("%d\n",++val);
    }
    return NULL;
}
int main()
{
    pthread_t id[5];
    int i=0;
    for(;i<5;i++)
    {
        pthread_create(&id[i],NULL,fun,(void*)&i);
    }
    for(i=0;i<5;i++)
    {
        pthread_join(id[i],NULL);
    }
    exit(0);
}

预期: 输出5000

结果如图:

这是因为线程是并发执行的,上一个线程对val进行++完,还没有写回内存,下个进程读取了之前的值对其++;

线程同步

1. 信号量

函数介绍

int sem_init(sem_t * sem, int pshared,unsigned int value)

sem: 指向的信号量对象

pshared: 0表示此信号为当前进程局部的,否则为多个进程间共享

value: 设置信号的值

int sem_wait(sem_t * sem)

进行p操作,信号值减1

sem: 指向的信号量对象

int sem_post(sem_t * sem)

进行v操作,信号值加1

sem: 指向的信号量对象

int sem_destory(sem_t * sem)

j清理该信号拥有的所有资源,成功返回0

sem: 指向的信号量对象

下面使用该方法对测试代码2修改

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>

int val = 0;
sem_t sig;
void* fun(void* arg)
{
    for(int i=0;i<1000;i++)
    {
        sem_wait(&sig);
        printf("%d\n",++val);
        sem_post(&sig);
    }
    return NULL;
}
int main()
{
    pthread_t id[5];
    sem_init(&sig,0,1);
    int i=0;
    for(;i<5;i++)
    {
        pthread_create(&id[i],NULL,fun,(void*)&i);
    }
    for(i=0;i<5;i++)
    {
        pthread_join(id[i],NULL);
    }
    sem_destroy(&sig);
    exit(0);
}

结果如图:

2.互斥锁

接口介绍:

1.int pthread_mutex_init(pthread_mutex_t* mutex,const pthread_mutexattr_t * mutexattr);

初始化锁
mutex: 互斥变量的指针
mutexattr: 设置互斥锁的属性

2.int pthread_mutex_lock(pthread_mutex_t* mutex);

上锁(加锁)

3.int pthread_mutex_unlock(pthread_mutex_t* mutex);

解锁

4.int pthread_mutex_destroy(pthread_mutex_t* mutex);

销毁锁

使用此方法修改测试代码2

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<semaphore.h>


int val = 0;
pthread_mutex_t mutex;
void* fun(void* arg)
{
    for(int i=0;i<1000;i++)
    {
        pthread_mutex_lock(&mutex);
        printf("%d\n",++val);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main()
{
    pthread_t id[5];
    pthread_mutex_init(&mutex,NULL);
    int i=0;
    for(;i<5;i++)
    {
        pthread_create(&id[i],NULL,fun,(void*)&i);
    }
    for(i=0;i<5;i++)
    {
        pthread_join(id[i],NULL);
    }
    pthread_mutex_destroy(&mutex);
    exit(0);

}

结果如图:

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

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

相关文章

ODC解读:数据脱敏在数据库协同开发的关键作用

肖杨 OceanBase生态产品研发工程师 OceanBase 生态产品研发工程师&#xff0c;山地骑行爱好者&#xff0c;ODC 团队核心成员&#xff0c;负责数据安全合规和系统集成&#xff0c;对 Java EE、 AI 大模型、MCU 芯片 等技术有着浓厚兴趣。 在数据库协同开发领域&#xff0c;敏感…

Spring MVC 七 - Locale 本地化

Spring各模块都支持国际化&#xff0c;SpringMVC也同样支持。DispatcherServlet通过Locale Resovler自动根据客户端的Locale支持国际化。 request请求上来后&#xff0c;DispatcherServlet查找并设置Locale Resovler&#xff0c;我们可以通过RequestContext.getLocale()获取到…

ipad手写笔哪个好用?电容笔性价比高的品牌

现今&#xff0c;使用电容笔的人越来越多&#xff0c;各大品牌厂商对于电容笔各种性能的设计也愈发用心。那么&#xff0c;电容笔哪个品牌性价比高&#xff1f;下面&#xff0c;我来给大家推荐几款好用又平价的电容笔&#xff0c;可以当个参考。 一、主动式电容笔和被动式电容…

mysql 密码修改

1、使用mysqladmin修改root密码 使用 mysqladmin 命令修改 MySQL 的 root 用户密码格式为 mysqladmin -u用户名 -p旧密码 password 新密码 注意&#xff1a;下图修改密码的命令中 -uroot 和 -proot 是整体&#xff0c;不要写成 -u root -p root&#xff0c;-u 和 root 间可以加…

分享一下蛋糕店怎么在微信小程序上开店

蛋糕店如何在微信小程序上开店 随着移动互联网的发展&#xff0c;微信小程序作为一种新型的商业模式&#xff0c;正逐渐成为各行各业拓展线上业务的重要手段。对于蛋糕店来说&#xff0c;利用微信小程序开店&#xff0c;不仅有利于拓展销售渠道&#xff0c;还能提高品牌知名度…

动漫小可爱-网页添加L2Dwidget.js

<!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>动漫小可爱</title><link rel"stylesh…

windows下MySQL服务不见,服务无法启动,服务闪退,提示“本地计算机上的MySQL服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止”

文章目录 前情提示1.解决MySQL服务消失2.解决MySQL服务无法启动 前情提示 后台启动MySQL服务出现闪退 或 “本地计算机上的MySQL服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止”&#xff0c;可以参考以下方法。 我的电脑上安装了双版本MySQL&#xff0c;这里…

Zabbix监控平台概念

1.概念 Zabbix是一款开源的、免费的、分布式监控平台支持web管理&#xff0c;WEB界面可以方便管理员使用可以监控硬件服务器CPU温度、风扇转速、操作系统CPU、EME、DISK、I/O、流量宽带、负载、端口、进程等Zabbix是C/S架构&#xff0c;Client客户端和Server端组成 2.Zabbix可…

2596. 检查骑士巡视方案(Java)

骑士在一张 n x n 的棋盘上巡视。在有效的巡视方案中&#xff0c;骑士会从棋盘的 左上角出发&#xff0c;并且访问棋盘上的每个格子恰好一次 。 给你一个 n x n 的整数矩阵 grid &#xff0c;由范围 [0, n * n - 1] 内的不同整数组成&#xff0c;其中 grid[row][col] 表示单元格…

碎片笔记 | 大模型攻防简报

前言&#xff1a;与传统的AI攻防&#xff08;后门攻击、对抗样本、投毒攻击等&#xff09;不同&#xff0c;如今的大模型攻防涉及以下多个方面的内容&#xff1a; 目录 一、大模型的可信问题1.1 虚假内容生成1.2 隐私泄露 二、大模型的模型安全问题&#xff08;传统AI攻防&…

vue中实现瀑布流布局

父组件 <template><WaterfallFlow :list"list"/> </template><script setup lang"ts">import WaterfallFlow from "/components/WaterfallFlow.vue"; import {reactive} from "vue"; type listType {height…

软考知识汇总--结构化开发方法

文章目录 1 结构化开发2 耦合3 内聚4 设计原则5 系统文档6 数据流图6.1 数据流图的基本图形元素 7 数据字典 1 结构化开发 结构化方法总的指导思想是自顶向下、逐层分解&#xff0c;它的基本原则是功能的分解与抽象。它是软件工程中最早出现的开发方法&#xff0c;特别适合于数…

Python Opencv实践 - LBP特征提取

参考资料&#xff1a; python skimage库LBP提取特征local_binary_pattern参数解释_local_binary_pattern函数_friedrichor的博客-CSDN博客 LBP特征笔记_亦枫Leonlew的博客-CSDN博客 import cv2 as cv import numpy as np import matplotlib.pyplot as plt from skimage.feat…

day39 注解 设计模式(单例模式和工厂模式)

一、注解 Target Target(ElementType.TYPE) Target({ ElementType.TYPE, ElementType.METHOD}) Target({ElementType.TYPE,//类ElementType.METHOD,//方法ElementType.FIELD,//属性 }) //确定自定义的注解的使用范围 type为类 method为方法 field为属性 Retentio…

【C++】仿函数和priority_queue(优先级队列)

目录 一、仿函数 二、priority_queue(优先级队列) 1、概念&#xff1a; 2、使用&#xff1a; 3、数组中第K个最大元素 4、priority_queue的模拟实现 一、仿函数 ①、概念&#xff1a; 仿函数&#xff0c;即函数对象。一种行为类似函数的对象&#xff0c;调用者可以像函…

Android studio 快捷键

目录 Ctrl N 搜索指定的 Java 类Ctrl F 查找文本Alt Enter 修复代码错误Ctrl Alt L 格式化代码Ctrl D 复制当前行或选中的内容Ctrl W 逐渐增加当前选中的范围Ctrl Shift - 折叠所有代码Ctrl Shift 展开所有代码Ctrl B 查看定义Ctrl Alt B 查看实现Ctrl Alt O …

Java版的数据结构——栈和队列

目录 1. 栈&#xff08;Stack&#xff09; 1.1 概念 1.2 栈的使用 1.3 栈的模拟实现 1.4 栈的应用场景 1.4.1 改变元素的序列 1.4.2 将递归转化为循环 2. 队列&#xff08;Queue&#xff09; 2.1 概念 2.2 队列的使用 2.3 队列模拟实现 2.4 循环队列 3. 双端队列&…

IO流(IO Stream)

​ 一、概述 我们已经系统学习了File 类&#xff0c;并且已经知道 File 类的实例用于表示文件或目录的路径 名。 虽然我们可以通过 File 实例来访问文件或目录的元数据&#xff0c;甚至可以创建、删除文件或目 录&#xff0c;但是&#xff0c;我们却不能通过File实例来访问文…

第六章 图 七、最短路径(BFS算法、Dijkstra算法、Floyd算法)

目录 一、BFS算法&#xff08;单源最短路径&#xff09; &#xff08;1&#xff09;介绍&#xff1a; &#xff08;2&#xff09;例子&#xff1a; 二、Dijkstra算法&#xff08;单源最短路径&#xff09; &#xff08;1&#xff09;介绍&#xff1a; &#xff08;2&#…

obsstudio下载使用

官网 Open Broadcaster Software | OBS 介绍 OBS是Open Broadcaster Software的简称&#xff0c;是一款开源&#xff0c;用于视频录制以及直播串流的软件&#xff0c;它支持Windows、Mac以及Linux操作系统。OBS使用容易、操作简单&#xff0c;对于新手小白来说非常友好。如果…