计算机网络与多线程同步机制详解

news2025/5/12 16:49:18

一、IP地址与子网划分

在互联网世界中,IP地址就像是每个设备的"门牌号",它使得数据包能够准确送达目的地。IP地址的划分与管理就像城市的规划,通过合理的子网划分,能够高效地管理网络资源。

子网掩码的工作原理

子网掩码用于区分IP地址中的网络部分和主机部分。举个生活中的例子:

想象一个大型小区,小区地址是"海淀区中关村大街123号"(网络地址),而具体到每个住户还需要楼号和门牌号(主机地址)。子网掩码就像是告诉邮递员:"这个地址的前几部分是小区的公共地址,后面的部分才是具体住户"。

IP地址: 192.168.1.34

子网掩码: 255.255.255.0 (或表示为/24)

在这个例子中,前24位(192.168.1)标识网络,最后8位(34)标识具体主机,就像是"A小区B栋34号"。

IP地址的分类

传统IP地址分为A、B、C、D、E五类,每类地址用于不同规模的网络:

  • A类:适合超大型网络,如大型跨国企业的内部网络
  • B类:适合中型网络,如区域性企业或大学校园网
  • C类:适合小型网络,如小型办公室或家庭网络
  • D类:用于多播
  • E类:保留作研究用途

二、多线程编程中的同步机制

在多线程编程中,不同线程之间共享资源的访问需要协调,就像多个人需要共用一个厨房或洗手间一样,需要有一套"规矩"来避免冲突。

临界区问题

临界区是指多个线程都需要访问的共享资源。想象一个办公室只有一台打印机,多个同事同时发送打印任务会导致打印内容混乱。这就是典型的临界区问题。

互斥锁(Mutex)

互斥锁就像是洗手间的门锁,一次只允许一个人使用:

template <typename T, typename... Args>

class Singleton {

public:

    static T* getInstance(Args... args) {

        if (!instance) {

            mutex.lock();  // 加锁

            if (!instance) {

                instance = new T(args...);

            }

            mutex.unlock();  // 解锁

        }

        return instance;

    }

private:

    static T* instance;

    static std::mutex mutex;

};

一家银行只有一个柜台,顾客需要排队等待前面的人办完业务才能轮到自己,这就是互斥原则。

信号量(Semaphore)

信号量更像是有限资源的管理器,可以控制同时访问资源的线程数量:

class Semaphore {

private:

    int count;

    std::mutex mtx;

    std::condition_variable cv;

    

public:

    Semaphore(int c = 0) : count(c) {}

    

    void wait() {

        std::unique_lock<std::mutex> lock(mtx);

        while(count == 0) {

            cv.wait(lock);

        }

        count--;

    }

    

    void signal() {

        std::unique_lock<std::mutex> lock(mtx);

        count++;

        cv.notify_one();

    }

};

电影院有100个座位,同时只能容纳100人观影。售票系统会跟踪剩余座位数,座位用完后,其他人必须等待有人离开才能进入。

条件变量(Condition Variable)

条件变量用于线程间的通知机制,比如生产者-消费者问题:

std::mutex mtx;

std::condition_variable cv;

std::queue<int> data_queue;

// 生产者线程

void producer() {

    for (int i = 0; i < 10; i++) {

        std::unique_lock<std::mutex> lock(mtx);

        data_queue.push(i);

        cv.notify_one();  // 通知消费者

    }

}

// 消费者线程

void consumer() {

    while (true) {

        std::unique_lock<std::mutex> lock(mtx);

        cv.wait(lock, []{ return !data_queue.empty(); });  // 等待队列非空

        int data = data_queue.front();

        data_queue.pop();

        // 处理数据...

    }

}

餐厅厨师(生产者)做好菜后会通知服务员(消费者)来取餐上菜。如果没有做好的菜,服务员就会等待;一旦有菜做好,厨师会通知服务员来取。

读写锁

读写锁允许多个线程同时读取共享资源,但写操作需要独占访问:

class ReadWriteLock {

private:

    std::mutex mtx;

    std::condition_variable cv;

    int readers = 0;

    bool writer = false;

    

public:

    void readLock() {

        std::unique_lock<std::mutex> lock(mtx);

        cv.wait(lock, [this]{ return !writer; });  // 等待没有写者

        readers++;

    }

    

    void readUnlock() {

        std::unique_lock<std::mutex> lock(mtx);

        readers--;

        if (readers == 0) {

            cv.notify_all();  // 如果没有读者了,通知可能在等待的写者

        }

    }

    

    void writeLock() {

        std::unique_lock<std::mutex> lock(mtx);

        cv.wait(lock, [this]{ return !writer && readers == 0; });  // 等待没有其他线程访问

        writer = true;

    }

    

    void writeUnlock() {

        std::unique_lock<std::mutex> lock(mtx);

        writer = false;

        cv.notify_all();  // 通知所有等待的线程

    }

};

图书馆的书籍可以被多人同时阅读(读操作),但当有人要更新书籍内容(写操作)时,必须确保没有人在阅读,而且只能一个人进行更新。

三、优先级调度与死锁问题

优先级反转

优先级反转是指高优先级任务被低优先级任务间接阻塞的情况。

生活例子:一个重要客户(高优先级)需要VIP服务,但负责VIP服务的工作人员正在处理一个普通客户(低优先级)的问题,而这个问题需要等待后勤人员(中优先级)的协助,导致重要客户必须等待普通客户的问题解决后才能得到服务。

死锁问题

死锁是指两个或多个线程互相持有对方需要的资源,导致所有线程都无法继续执行。


// 潜在的死锁代码

void thread1() {

    lock(mutex1);

    // 一些操作...

    lock(mutex2);  // 可能导致死锁

    // 更多操作...

    unlock(mutex2);

    unlock(mutex1);

}

void thread2() {

    lock(mutex2);

    // 一些操作...

    lock(mutex1);  // 可能导致死锁

    // 更多操作...

    unlock(mutex1);

    unlock(mutex2);

}

两条狭窄的单行道互相交叉,两辆车分别占据一条道的入口,都想通过对方的道路继续前进,结果谁都无法移动。

避免死锁的策略

  1. 资源排序:按固定顺序申请资源
  1. 超时机制:资源获取设置超时,超时后释放已持有资源并重试
  1. 死锁检测:系统定期检查是否存在死锁,发现后强制终止某些线程
  1. 死锁预防:设计时避免死锁的四个必要条件之一

实战应用:生产者-消费者问题完整实现

生产者-消费者是一个经典的多线程协作问题,类似于餐厅的厨师和服务员关系。以下是一个完整的C++实现:


#include <iostream>

#include <queue>

#include <thread>

#include <mutex>

#include <condition_variable>

const int BUFFER_SIZE = 10;

class Buffer {

private:

    std::queue<int> data;

    std::mutex mtx;

    std::condition_variable not_full;

    std::condition_variable not_empty;

    int capacity;

    

public:

    Buffer(int cap) : capacity(cap) {}

    

    void produce(int item) {

        std::unique_lock<std::mutex> lock(mtx);

        not_full.wait(lock, [this]{ return data.size() < capacity; });

        

        data.push(item);

        std::cout << "生产: " << item << std::endl;

        

        lock.unlock();

        not_empty.notify_one();

    }

    

    int consume() {

        std::unique_lock<std::mutex> lock(mtx);

        not_empty.wait(lock, [this]{ return !data.empty(); });

        

        int item = data.front();

        data.pop();

        std::cout << "消费: " << item << std::endl;

        

        lock.unlock();

        not_full.notify_one();

        return item;

    }

};

void producer(Buffer& buffer, int start, int count) {

    for (int i = 0; i < count; i++) {

        buffer.produce(start + i);

        std::this_thread::sleep_for(std::chrono::milliseconds(100));

    }

}

void consumer(Buffer& buffer, int count) {

    for (int i = 0; i < count; i++) {

        buffer.consume();

        std::this_thread::sleep_for(std::chrono::milliseconds(200));

    }

}

int main() {

    Buffer buffer(BUFFER_SIZE);

    

    std::thread p1(producer, std::ref(buffer), 0, 10);

    std::thread p2(producer, std::ref(buffer), 100, 10);

    std::thread c1(consumer, std::ref(buffer), 10);

    std::thread c2(consumer, std::ref(buffer), 10);

    

    p1.join();

    p2.join();

    c1.join();

    c2.join();

    

    return 0;

}

总结

计算机网络和多线程编程是现代软件开发中不可或缺的基础知识。理解IP地址与子网划分有助于我们设计高效的网络架构;掌握多线程同步机制则能帮助我们开发出高性能、安全的并发程序。

通过将这些抽象概念与日常生活中的例子关联起来,我们可以更直观地理解它们的作用和重要性。无论是网络通信还是多线程编程,核心都是协调和资源管理的艺术。

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

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

相关文章

Python训练营打卡——DAY22(2025.5.11)

复习日 学习参考如何使用kaggle平台&#xff0c;写下使用注意点&#xff0c;并对下述比赛提交代码 泰坦尼克号——来自灾难的机器学习 数据来源&#xff1a; kaggle泰坦里克号人员生还预测 挑战 泰坦尼克号沉没是历史上最臭名昭著的海难之一。 1912年4月15日&#xff0c;在被普…

实战项目4(05)

​目录 任务场景一 【sw1配置】 任务场景二 【sw1配置】 【sw2配置】 任务场景一 按照下图完成网络拓扑搭建和配置 任务要求&#xff1a; 1、在交换机SW1的E0/0/1端口进行设置&#xff0c;实现允许最多两个电脑可以正常进行通信。 2、在交换机SW1的E0/0/2端口进行设置&…

C++学习之STL学习

在经过前面的简单的C入门语法的学习后&#xff0c;我们开始接触C最重要的组成部分之一&#xff1a;STL 目录 STL的介绍 什么是STL STL的历史 UTF-8编码原理&#xff08;了解&#xff09; UTF-8编码原理 核心编码规则 规则解析 编码步骤示例 1. 确定码点范围 2. 转换为…

3. 仓颉 CEF 库封装

文章目录 1. capi 使用说明2. Cangjie CEF2. 1实现目标 3. 实现示例 1. capi 使用说明 根据上一节 https://blog.csdn.net/qq_51355375/article/details/147880718?spm1011.2415.3001.5331 所述&#xff0c; cefcapi 是libcef 共享库导出一个 C API, 而以源代码形式分发的 li…

LabVIEW多通道并行数据存储系统

在工业自动化监测、航空航天测试、生物医学信号采集等领域&#xff0c;常常需要对多个传感器通道的数据进行同步采集&#xff0c;并根据后续分析需求以不同采样率保存特定通道组合。传统单线程数据存储方案难以满足实时性和资源利用效率的要求&#xff0c;因此设计一个高效的多…

谷歌在即将举行的I/O大会之前,意外泄露了其全新设计语言“Material 3 Expressive”的细节

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

十三、基于大模型的在线搜索平台——整合function calling流程

基于大模型的在线搜索平台——整合function calling流程 一、function calling调用总结 上篇文章已经实现了信息抓取能力&#xff0c;并封装成了函数。现在最后一步将能力转换为大模型可以调用的能力&#xff0c;实现搜索功能就可以了。这篇主要实现大模型的function calling能…

力扣70题解

记录 2025.5.8 题目: 思路&#xff1a; 1.初始化&#xff1a;p 和 q 初始化为 0&#xff0c;表示到达第 0 级和第 1 级前的方法数。r 初始化为 1&#xff0c;表示到达第 1 级台阶有 1 种方法。 2.循环迭代&#xff1a;从第 1 级到第 n 级台阶进行迭代&#xff1a; p 更新为前…

电商双11美妆数据分析

1、初步了解 2.2 缺失值处理 通过上面观察数据发现sale_count,comment_count 存在缺失值,先观察存在缺失值的行的基本情况 2.3 数据挖掘寻找新的特征 给出各个关键词的分类类别 由title新生成两列类别 对是否是男性专用进行分析并新增一列 对每个产品总销量新增销售额这一列

24、TypeScript:预言家之书——React 19 类型系统

一、预言家的本质 "TypeScript是魔法世界的预言家之书&#xff0c;用静态类型编织代码的命运轨迹&#xff01;" 霍格沃茨符文研究院的巫师挥动魔杖&#xff0c;类型注解与泛型的星轨在空中交织成防护矩阵。 ——基于《国际魔法联合会》第12号类型协议&#xff0c;Ty…

第8章-1 查询性能优化-优化数据访问

上一篇&#xff1a;《第7章-3 维护索引和表》 在前面的章节中&#xff0c;我们介绍了如何设计最优的库表结构、如何建立最好的索引&#xff0c;这些对于提高性能来说是必不可少的。但这些还不够——还需要合理地设计查询。如果查询写得很糟糕&#xff0c;即使库表结构再合理、索…

PCL点云按指定方向进行聚类(指定类的宽度)

需指定方向和类的宽度。测试代码如下&#xff1a; #include <iostream> #include <fstream> #include <vector> #include <string> #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/visualization/pcl_visu…

C#对SQLServer增删改查

1.创建数据库 2.SqlServerHelper using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks;namespace WindowsFormsApp1 {internal class SqlServerHelper{//…

模拟太阳系(C#编写的maui跨平台项目源码)

源码下载地址&#xff1a;https://download.csdn.net/download/wgxds/90789056 本资源为用C#编写的maui跨平台项目源码&#xff0c;使用Visual Studio 2022开发环境&#xff0c;基于.net8.0框架&#xff0c;生成的程序为“模拟太阳系运行”。经测试&#xff0c;生成的程序可运行…

蓝桥杯14届 数三角

问题描述 小明在二维坐标系中放置了 n 个点&#xff0c;他想在其中选出一个包含三个点的子集&#xff0c;这三个点能组成三角形。然而这样的方案太多了&#xff0c;他决定只选择那些可以组成等腰三角形的方案。请帮他计算出一共有多少种选法可以组成等腰三角形&#xff1f; 输…

HTML12:文本框和单选框

表单元素格式 属性说明type指定元素的类型。text、password、 checkbox、 radio、submit、reset、file、hidden、image 和button&#xff0c;默认为textname指定表单元素的名称value元素的初始值。type为radio时必须指定一个值size指定表单元素的初始宽度。当type为text 或pas…

机器人厨师上岗!AI在餐饮界掀起新风潮!

想要了解人工智能在其他各个领域的应用&#xff0c;可以查看下面一篇文章 《AI在各领域的应用》 餐饮业是与我们日常生活息息相关的行业&#xff0c;而人工智能&#xff08;AI&#xff09;正在迅速改变这个传统行业的面貌。从智能点餐到食材管理&#xff0c;再到个性化推荐&a…

MySQL开篇

文章目录 一、前置知识1. MySQL的安装2. 前置一些概念知识 二、MySQL数据库操作2.1 概念2.2 数据库的操作2.2.1创建数据库命令2.2.2 查看数据库2.2.3 选中数据库2.2.4 删除数据库 三、MySQL数据表操作3.1 概念3.2 数据表的操作3.2.1 创建表 一、前置知识 1. MySQL的安装 MySQ…

Linux电脑本机使用小皮面板集成环境开发调试WEB项目

开发调试WEB项目&#xff0c;有时开发环境配置繁琐&#xff0c;可以使用小皮面板集成环境。 小皮面板官网&#xff1a; https://www.xp.cn/1.可以使用小皮面板安装脚本一键安装。登陆小皮面板管理后台 2.在“软件商店”使用LNMP一键部署集成环境。 3.添加网站&#xff0c;本…

问题及解决01-面板无法随着窗口的放大而放大

在MATLAB的App Designer中&#xff0c;默认情况下&#xff0c;组件的位置是固定的&#xff0c;不会随着父容器的大小变化而改变。问题图如下图所示。 解决&#xff1a; 为了让Panel面板能够随着UIFigure父容器一起缩放&#xff0c;需要使用布局管理器&#xff0c;我利用 MATLA…