【嵌入式Linux应用开发基础】进程间通信(1):管道

news2025/5/12 13:12:58

目录

一、管道的基本概念

二、管道的工作原理

三、管道的类型

3.1. 匿名管道(Anonymous Pipe)

3.2. 命名管道(Named Pipe,FIFO)

四、管道的读写规则

4.1. 匿名管道的读写规则

4.2. 命名管道的读写规则

五、管道的优缺点

5.1. 优点

5.2. 缺点

六、常见问题

6.1. 什么是管道(Pipe)?匿名管道和命名管道(FIFO)的区别是什么?

6.2. 为什么写管道时进程会被阻塞?如何避免?

6.3. 如何确定管道缓冲区大小?单次写入数据超过缓冲区会怎样?

6.4. 命名管道(FIFO)的读写端打开顺序问题

6.5. 如何处理管道破裂(Broken Pipe)错误?

6.6. 多进程/线程同时读写管道的同步问题

6.7. 管道与Shell命令的结合使用

6.8. 如何选择管道与其他IPC方式(如消息队列、共享内存)?

七、参考资料


Linux进程间通信(Inter-Process Communication,IPC)是指不同进程间进行数据交换和信息传递的机制。它允许多个进程共享资源、同步执行、模块化设计及数据传递。常见的IPC方式包括管道、消息队列、共享内存、信号量、套接字等。这些方式各有特点,适用于不同的应用场景,是实现进程间高效协作的关键。本篇主要学习管道部分。

一、管道的基本概念

  • 管道是一种半双工的通信方式,数据只能单向流动,即数据从管道的一端写入,从另一端读出。通常把写入数据的一端称为写端(write end),读出数据的一端称为读端(read end)
  • 管道可以用于具有亲缘关系的进程之间的通信,比如父子进程,也可以在没有亲缘关系的进程间通过命名管道(FIFO)实现通信。

在 Linux 系统中,管道本质上是一种特殊的文件,它在内存中开辟了一段缓存空间来存储数据,遵循先进先出(FIFO)的原则,就像一个队列,先写入管道的数据会先被读出。

二、管道的工作原理

①创建管道:在Linux中,可以使用pipe()系统调用来创建一个管道。pipe()函数接受一个指向int类型数组的指针作为参数,该数组将包含两个文件描述符:一个用于读(fd[0]),另一个用于写(fd[1])

②数据传递

  • 当一个进程向管道的写端写入数据时,操作系统会将数据放入一个内核缓冲区中。

  • 另一个进程可以从管道的读端读取数据,操作系统会从内核缓冲区中取出数据并传递给该进程。

③同步与阻塞

  • 写端阻塞:如果管道的缓冲区已满,且写端进程继续尝试写入数据,则写操作将被阻塞,直到缓冲区中有足够的空间为止。

  • 读端阻塞:如果管道的缓冲区为空,且读端进程尝试读取数据,则读操作将被阻塞,直到缓冲区中有数据为止。

  • 可以通过关闭不再使用的文件描述符来解除阻塞状态。

④生命周期:管道的生命周期随进程而存在。当所有使用管道的文件描述符都被关闭时,管道将被销毁。

⑤管道关闭:当进程不再需要使用管道时,应该关闭相应的文件描述符。当所有指向管道的文件描述符都被关闭后,管道所占用的内核资源会被释放。

⑥使用示例:在命令行中,可以使用管道符号|将多个命令连接起来,使得一个命令的输出直接作为另一个命令的输入。例如,ls | grep "txt"命令会列出当前目录下的所有文件,并通过grep命令筛选出包含"txt"字符串的文件名。

三、管道的类型

3.1. 匿名管道(Anonymous Pipe)

  • 原理与特点:匿名管道只能用于具有亲缘关系的进程之间,比如父子进程。它在创建时没有名字,生命周期与创建它的进程相关联。当创建匿名管道的进程结束时,管道也会随之被销毁。

  • 创建与使用:在 C 语言中,可以使用pipe()系统调用创建匿名管道。pipe()函数的原型为:

int pipe(int pipefd[2]);
  •  函数会返回两个文件描述符,存储在pipefd数组中,pipefd[0]指向管道的读端,pipefd[1]指向管道的写端。
  • 如果创建成功,pipe()函数返回 0;
  • 若失败,则返回 - 1,并设置errno以指示错误原因。

下面是一个简单的父子进程通过匿名管道通信的示例代码:

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

int main() {
    int pipe_fd[2];
    pid_t pid;
    char buffer[1024];

    // 创建匿名管道
    if (pipe(pipe_fd) == -1) {
        perror("pipe");
        return 1;
    }

    // 创建子进程
    pid = fork();
    if (pid == -1) {
        perror("fork");
        return 1;
    } else if (pid == 0) {
        // 子进程关闭读端
        close(pipe_fd[0]);
        // 向管道写端写入数据
        write(pipe_fd[1], "Hello, parent!", 14);
        // 关闭写端
        close(pipe_fd[1]);
    } else {
        // 父进程关闭写端
        close(pipe_fd[1]);
        // 从管道读端读取数据
        ssize_t bytes_read = read(pipe_fd[0], buffer, sizeof(buffer));
        if (bytes_read > 0) {
            buffer[bytes_read] = '\0';
            printf("Parent received: %s\n", buffer);
        }
        // 关闭读端
        close(pipe_fd[0]);
    }
    return 0;
}

首先通过pipe()创建匿名管道,然后使用fork()创建子进程。子进程关闭读端,向写端写入数据;父进程关闭写端,从读端读取数据。通过这种方式,实现了父子进程之间的通信。

3.2. 命名管道(Named Pipe,FIFO)

  • 原理与特点:命名管道也叫 FIFO(First - In - First - Out),它突破了匿名管道只能用于亲缘关系进程间通信的限制。FIFO 在文件系统中以特殊文件的形式存在,有自己的文件名,不同进程只要能访问该文件,就可以通过它进行通信。命名管道的生命周期独立于创建它的进程,直到被显式删除。

  • 创建与使用:在 C 语言中,可以使用mkfifo()函数创建命名管道。mkfifo()函数原型为:

int mkfifo(const char *pathname, mode_t mode);

其中pathname是命名管道的路径名,mode指定管道的权限。创建成功时返回 0,失败返回 - 1。

以下是一个使用命名管道进行通信的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

#define FIFO_NAME "my_fifo"

int main() {
    int fd;
    char buffer[1024];

    // 创建命名管道
    if (mkfifo(FIFO_NAME, 0666) == -1 && errno!= EEXIST) {
        perror("mkfifo");
        return 1;
    }

    // 打开命名管道进行读操作
    fd = open(FIFO_NAME, O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 从命名管道读取数据
    ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
    if (bytes_read > 0) {
        buffer[bytes_read] = '\0';
        printf("Received: %s\n", buffer);
    }

    // 关闭文件描述符
    close(fd);

    // 删除命名管道
    if (unlink(FIFO_NAME) == -1) {
        perror("unlink");
        return 1;
    }

    return 0;
}

先使用mkfifo()创建名为my_fifo的命名管道,然后使用open()打开管道进行读操作,从管道中读取数据并打印,最后使用unlink()删除命名管道。

四、管道的读写规则

4.1. 匿名管道的读写规则

①读规则

  • 管道无数据时:当管道中没有数据可读时,读操作会阻塞,即读进程会暂停执行,直到管道中有数据可供读取或者管道的写端被关闭。若所有写端都已关闭,读操作将返回 0,表示读到了文件末尾。

  • 管道有数据时:读操作会按照先进先出(FIFO)的顺序从管道中读取数据。若读请求的字节数小于等于管道中当前的数据量,读操作会成功读取请求的字节数。若读请求的字节数大于管道中当前的数据量,读操作会读取管道中现有的所有数据。

②写规则

  • 管道读端打开时:只要管道的读端处于打开状态,写操作就会尝试将数据写入管道。若管道的缓冲区有足够空间,写操作会立即完成,将数据写入管道缓冲区,并返回实际写入的字节数。若管道缓冲区已满,写操作会阻塞,直到管道中的数据被读走,腾出足够空间。

  • 管道读端关闭时:如果管道的所有读端都已关闭,此时再进行写操作,操作系统会向写进程发送 SIGPIPE 信号,通常情况下,进程会收到该信号而异常终止。

4.2. 命名管道的读写规则

①读规则

  • 管道无数据且写端未打开时:如果命名管道中没有数据,并且所有写端都没有打开,读操作的行为取决于打开管道的方式。若以阻塞方式打开(默认方式),读操作会阻塞,直到有写进程打开管道并写入数据或者有信号中断读操作。若以非阻塞方式打开(使用 O_NONBLOCK 标志),读操作不会阻塞,而是立即返回 - 1,同时将 errno 设置为 EAGAIN 或 EWOULDBLOCK,表示暂时没有数据可读。

  • 管道有数据时:与匿名管道类似,读操作会按照 FIFO 顺序从管道中读取数据,根据读请求的字节数和管道中数据量的情况,决定实际读取的字节数。

②写规则

  • 管道读端打开时:只要命名管道的读端有进程打开,写操作就会尝试将数据写入管道。若管道缓冲区有空间,写操作会立即完成并返回实际写入的字节数;若缓冲区已满,写操作的阻塞行为与匿名管道类似,取决于管道是否以非阻塞方式打开。

  • 管道读端未打开时:如果命名管道的读端没有任何进程打开,以阻塞方式打开管道的写操作会阻塞,直到有读进程打开管道。以非阻塞方式打开管道的写操作则会立即返回 - 1,同时将 errno 设置为 ENXIO,表示没有连接的设备。

、管道的优缺点

5.1. 优点

  • 简单易用:管道的使用相对简单,创建和操作管道的系统调用较为直观,不需要复杂的配置和初始化过程。在 C 语言中,使用pipe()函数就可以轻松创建一个匿名管道,进程可以方便地通过管道进行数据传输,对于简单的进程间通信场景,能够快速实现数据的传递和共享。

  • 数据传输高效:管道在内核中实现了数据的缓冲机制,数据可以在管道的缓冲区中暂存,使得数据的发送和接收更加平滑。数据从写端写入后,读端可以及时读取,不需要额外的同步机制来保证数据的完整性和顺序性,在进程间传输大量数据时,能够提供较高的传输效率。

  • 自带同步与互斥机制:管道本身具有一定的同步和互斥特性。当管道缓冲区满时,写操作会阻塞,直到读端读取数据腾出空间;当管道缓冲区为空时,读操作会阻塞,直到写端写入数据。这种机制保证了数据的正确读写顺序,避免了数据竞争和冲突,使得进程间的数据交互更加稳定和可靠。

  • 父子进程通信方便:在创建子进程时,父进程可以通过管道将数据传递给子进程,或者子进程将处理结果通过管道返回给父进程。这种方式为父子进程之间的通信提供了一种便捷的途径,例如在 Shell 脚本中,经常会利用管道来实现父子进程之间的命令执行和结果传递。

5.2. 缺点

  • 半双工通信限制:管道通常是半双工的,即数据只能在一个方向上流动。如果需要实现双向通信,就需要创建两个管道,这会增加程序的复杂性和资源开销。

  • 只能用于亲缘关系进程:匿名管道只能用于具有亲缘关系的进程之间,如父子进程,这限制了它的应用范围。虽然命名管道可以用于无亲缘关系的进程,但它需要在文件系统中创建一个特殊的文件,会带来一定的复杂性和安全性问题。

  • 数据缓存大小有限:管道的缓冲区大小是有限的,不同的系统对管道缓冲区大小的默认值有所不同。如果进程写入管道的数据量超过了缓冲区的容量,写操作就会阻塞,直到读端及时读取数据腾出空间。这可能会导致写进程长时间等待,影响程序的性能和响应速度。

  • 没有数据边界:管道中的数据是无边界的字节流,读端无法区分数据的边界和不同的消息。这就要求应用程序在设计时,需要自己定义数据的格式和边界标识,以便正确地解析和处理数据,增加了应用程序开发的难度和复杂性。

综上所述,在嵌入式Linux应用开发中,管道作为进程间通信的基础方式意义重大。它分为匿名管道和命名管道,前者用于亲缘进程,创建简单,通过`pipe()`函数实现;后者突破进程关系限制,在文件系统以特殊文件存在,用`mkfifo()`创建。管道读写遵循特定规则,虽有半双工、缓存有限等不足,但胜在简单高效,是实现进程间数据传递的重要工具。

六、常见问题

6.1. 什么是管道(Pipe)?匿名管道和命名管道(FIFO)的区别是什么?

  • 管道是Linux中一种半双工的进程间通信(IPC)方式,数据单向流动。

  • 匿名管道(Anonymous Pipe)

    • 仅用于有亲缘关系的进程(如父子进程)。

    • 通过pipe()系统调用创建,返回两个文件描述符:fd[0](读端)和fd[1](写端)。

    • 生命周期随进程结束。

  • 命名管道(Named Pipe/FIFO)

    • 通过mkfifo命令或mkfifo()函数创建,存在于文件系统中(如/tmp/myfifo)。

    • 允许无亲缘关系的进程通信。

    • 需显式删除(unlink())或随系统重启消失。

// 匿名管道示例
int fd[2];
pipe(fd);  // 创建管道
if (fork() == 0) { 
    close(fd[0]);  // 子进程关闭读端
    write(fd[1], "Hello", 6);
} else {
    close(fd[1]);  // 父进程关闭写端
    char buf[6];
    read(fd[0], buf, 6);
}

6.2. 为什么写管道时进程会被阻塞?如何避免?

  • 阻塞场景

    • 当管道缓冲区已满时,写操作(write())会阻塞。

    • 读端未打开时,写操作会触发SIGPIPE信号(默认终止进程)。

  • 解决方案

    • 使用fcntl()设置非阻塞模式:

      fcntl(fd, F_SETFL, O_NONBLOCK);
    • 多路复用(如select()/poll())监控管道状态。

    • 确保读端及时读取数据。 

6.3. 如何确定管道缓冲区大小?单次写入数据超过缓冲区会怎样?

  • 通过fcntl(fd, F_GETPIPE_SZ)获取缓冲区大小(默认通常为64KB)。

  • 若写入数据超过缓冲区:

    • 阻塞模式下,write()会等待直到有空间。

    • 非阻塞模式下,write()返回EAGAIN错误。

  • 关键规则:单次write()数据量 ≤ PIPE_BUF(通常4KB)时,操作是原子性的;否则数据可能被分割。

6.4. 命名管道(FIFO)的读写端打开顺序问题

  • 问题:若读端未打开时写端尝试写入,会发生什么?

    • 默认情况下,写端open()阻塞,直到读端打开。

    • 可通过O_NONBLOCK标志避免阻塞:

int fd = open("/tmp/myfifo", O_WRONLY | O_NONBLOCK);
  • 若读端全部关闭,写操作会触发SIGPIPE信号。

6.5. 如何处理管道破裂(Broken Pipe)错误?

  • 场景:读端已关闭,写端继续写入。

    • write()会返回EPIPE错误,并触发SIGPIPE信号(默认终止进程)。

    • 解决方案

      1. 忽略SIGPIPE信号:

        signal(SIGPIPE, SIG_IGN);
      2. 检查write()返回值,处理EPIPE错误: 

        if (write(fd, buf, len) == -1) {
            if (errno == EPIPE) {
                // 处理管道破裂
            }
        }

6.6. 多进程/线程同时读写管道的同步问题

  • 匿名管道:同一时刻只能有一个读端和一个写端,多进程需协调。

  • 命名管道:多个写进程需保证数据原子性(单次写入 ≤ PIPE_BUF)。

  • 建议

    • 使用PIPE_BUF大小限制保证原子性。

    • 通过外部锁(如文件锁)或信号量同步。

6.7. 管道与Shell命令的结合使用

  • 示例:在Shell中使用管道连接命令:

mkfifo /tmp/myfifo
cat /tmp/myfifo &  # 后台启动读端
echo "Hello" > /tmp/myfifo
  • 注意:Shell重定向会隐式处理打开顺序和阻塞问题。

6.8. 如何选择管道与其他IPC方式(如消息队列、共享内存)?

  • 管道适用场景

    • 简单单向数据流。

    • 父子进程或少量数据通信。

  • 不适用场景

    • 高频大数据量(优先考虑共享内存)。

    • 复杂结构化数据(考虑消息队列或Socket)。


七、参考资料

  • 《Unix 环境高级编程(第 3 版)》
    • 作者:W. Richard Stevens、Stephen A. Rago
    • 简介:这是 Unix 和类 Unix 系统编程领域的经典著作,详细讲解了 Unix 系统的各种特性,其中对管道的创建、使用、读写规则等有深入且全面的阐述。
  • 《Linux 系统编程》
    • 作者:Robert Love
    • 简介:专注于 Linux 系统下的编程技术,对 Linux 进程间通信机制进行了细致介绍,涉及管道的底层原理、与其他 IPC 机制的对比等内容。
  • Linux 手册页
    • 获取方式:在 Linux 系统终端使用man命令,如man pipeman mkfifo查看相关内容;也可访问man7.org在线查看。
    • 简介:这是最权威的 Linux 系统调用参考资料,关于管道相关系统调用的手册页详细说明了函数原型、参数、返回值和使用示例,是学习管道编程的重要依据。
  • GNU C Library 文档
    • 获取方式:访问GNU 官方网站。
    • 简介:GNU C Library 是 Linux 系统广泛使用的 C 标准库,其文档对与管道操作相关的库函数进行了详细描述。

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

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

相关文章

【DeepSeek】Mac m1电脑部署DeepSeek

一、电脑配置 个人电脑配置 二、安装ollama 简介&#xff1a;Ollama 是一个强大的开源框架&#xff0c;是一个为本地运行大型语言模型而设计的工具&#xff0c;它帮助用户快速在本地运行大模型&#xff0c;通过简单的安装指令&#xff0c;可以让用户执行一条命令就在本地运…

DHCP详解,网络安全零基础入门到精通实战教程!

一、DHCP简介 DHCP(Dynamic Host Configuration Protocol),动态主机配置协议&#xff0c;是一个应用层协议。当我们将客户主机ip地址设置为动态获取方式时&#xff0c;DHCP服务器就会根据DHCP协议给客户端分配IP&#xff0c;使得客户机能够利用这个IP上网。 DHCP前身是BOOTP&am…

【Prometheus】prometheus结合pushgateway实现脚本运行状态监控

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

立创实战派ESP32-S3烧录小智AI指南

小智 AI 聊天机器人-开源项目介绍 本项目是一个开源项目&#xff0c;主要用于教学目的。我们希望通过这个项目&#xff0c;能够帮助更多人入门 AI 硬件开发&#xff0c;了解如何将当下飞速发展的大语言模型应用到实际的硬件设备中。无论你是对 AI 感兴趣的学生&#xff0c;还是…

深度学习的集装箱箱号OCR识别技术,识别率99.9%

集装箱箱号OCR识别技术是一项结合计算机视觉和规则校验的复杂任务&#xff0c;以下是其关键要点及实现思路的总结&#xff1a; 1、集装箱号结构&#xff1a;11位字符&#xff0c;格式为公司代码(3字母)和序列号(6数字)以及校验码(1数字)和尺寸/类型代码(可选)&#xff0c;例如…

如何在Windows下使用Ollama本地部署DeepSeek R1

参考链接&#xff1a; 通过Ollama本地部署DeepSeek R1以及简单使用的教程&#xff08;超详细&#xff09; 【DeepSeek应用】DeepSeek R1 本地部署&#xff08;OllamaDockerOpenWebUI&#xff09; 如何将 Chatbox 连接到远程 Ollama 服务&#xff1a;逐步指南 首先需要安装oll…

【分布式理论12】事务协调者高可用:分布式选举算法

文章目录 一、分布式系统中事务协调的问题二、分布式选举算法1. Bully算法2. Raft算法3. ZAB算法 三、小结与比较 一、分布式系统中事务协调的问题 在分布式系统中&#xff0c;常常有多个节点&#xff08;应用&#xff09;共同处理不同的事务和资源。前文 【分布式理论9】分布式…

postgres源码学习之简单sql查询

postgres源码学习之sql查询 sql查询的主流程读取sql解析sql重写sql获得执行计划执行查询操作结果返回 sql查询的主流程 参考postgres的处理流程 由上一节&#xff0c;我们可以看到&#xff0c;当有新的连接通过权限认证之后&#xff0c;将进入等待接收sql语句&#xff0c;并执…

C#项目05-猜数字多线程

本项目利用多线程&#xff0c;通过点击按钮猜数字&#xff0c; 知识点 线程 基本概念 进程:一组资源&#xff0c;构成一个正在运行的程序&#xff0c;这些资源包括地址空间、文件句柄以及程序启动需要的其他东西的载体。 线程:体现一个程序的真实执行情况&#xff0c; 线…

《C语言动态顺序表:从内存管理到功能实现》

1.顺序表 1.1 概念 顺序存储的线性表&#xff0c;叫顺序表。 1.2顺序表存放的实现方式 可以使用数组存储数据&#xff0c;可以实现逻辑上相连&#xff0c;物理内存上也相连。也可以使用malloc在堆区申请一片连续的空间&#xff0c;存放数据&#xff0c;实现逻辑上相连&#…

通过API 调用本地部署 deepseek-r1 模型

如何本地部署 deepseek 请参考&#xff08;windows 部署安装 大模型 DeepSeek-R1&#xff09; 那么实际使用中需要开启API模式&#xff0c;这样可以无拘无束地通过API集成的方式&#xff0c;集成到各种第三方系统和应用当中。 上遍文章是基于Ollama框架运行了deepSeek R1模型…

DeepSeek-学习与实践

1.应用场景 主要用于学习与使用DeepSeek解决问题, 提高效率. 2.学习/操作 1.文档阅读 文档 DeepSeek -- 官网, 直接使用 --- 代理网站 --- 极客智坊 https://poe.com/DeepSeek-R1 https://time.geekbang.com/search?qdeepseek -- 搜索deepseek的资料 资料 20250209DeepSeekC…

撕碎QT面具(6):调节窗口大小后,控件被挤得重叠的解决方法

问题&#xff1a;控件重叠 分析原因&#xff1a;因为设置了最小大小&#xff0c;所以界面中的大小不会随窗口的变化而自动变化。 处理方案&#xff1a;修改mimumSize的宽度与高度为0&#xff0c;并设置sizePolicy为Expanding&#xff0c;让其自动伸缩。 结果展示&#xff08;自…

解锁机器学习核心算法 | K-平均:揭开K-平均算法的神秘面纱

一、引言 机器学习算法种类繁多&#xff0c;它们各自有着独特的优势和应用场景。前面我们学习了线性回归算法、逻辑回归算法、决策树算法。而今天&#xff0c;我们要深入探讨的是其中一种经典且广泛应用的聚类算法 —— K - 平均算法&#xff08;K-Means Algorithm&#xff09…

【Linux】匿名管道的应用场景-----管道进程池

目录 一、池化技术 二、简易进程池的实现&#xff1a; Makefile task.h task.cpp Initchannel函数&#xff1a; 创建任务&#xff1a; 控制子进程&#xff1a; 子进程执行任务&#xff1a; 清理收尾&#xff1a; 三、全部代码&#xff1a; 前言&#xff1a; 对于管…

PostgreSQL的学习心得和知识总结(一百六十九)|深入理解PostgreSQL数据库之 Group By 键值消除 的使用和实现

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

Python基于循环神经网络的情感分类系统(附源码,文档说明)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

Zookeeper应用案例-分布式锁-实现思路

以下是具体实现代码 第一步&#xff1a;注册锁节点 第二步&#xff1a;获取锁节点&#xff0c;如果自己是最小的节点&#xff0c;就获取权限 第三步&#xff1a;拿到锁就开始自己的业务逻辑 第四步&#xff1a;业务逻辑好了就要释放这把锁 第五步&#xff1a;重新注册监听&…

java练习(32)

ps&#xff1a;题目来自力扣 环形链表 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表…

伯克利 CS61A 课堂笔记 10 —— Trees

本系列为加州伯克利大学著名 Python 基础课程 CS61A 的课堂笔记整理&#xff0c;全英文内容&#xff0c;文末附词汇解释。 目录 01 Trees 树 Ⅰ Tree Abstraction Ⅱ Implementing the Tree Abstraction 02 Tree Processing 建树过程 Ⅰ Fibonacci tree Ⅱ Tree Process…