线程基础与生产者消费者模型实践

在现代计算领域,多线程编程是提高程序效率和响应性的关键技术之一。本文将深入浅出地介绍线程的基本概念、线程同步机制,特别是互斥锁和条件变量,并通过实现一个经典的“生产者消费者”问题示例来展示这些概念的实际应用

线程基础

线程定义

线程是操作系统调度的最小单位,是进程内的一个执行路径。每个线程拥有独立的栈空间、程序计数器等资源,但共享所属进程的地址空间、全局变量等资源。

线程调度

操作系统通过调度器管理线程的执行,为每个线程分配时间片。时间片的长度直接影响系统的响应性和吞吐量。

线程同步

多线程环境下,为了防止数据竞争和死锁,需要引入同步机制。主要包括互斥锁、信号量、条件变量等。

 互斥锁与条件变量

互斥锁

互斥锁(Mutex)用于保护临界区资源,确保同一时刻只有一个线程可以访问共享资源。例如,pthread_mutex_lock()pthread_mutex_unlock() 函数分别用于加锁和解锁。

条件变量

条件变量(Condition Variable)用于线程间的同步,当线程需要等待某个条件成立时,可以使用条件变量进入休眠,直到其他线程通知条件满足。主要函数包括 pthread_cond_wait()pthread_cond_signal()

生产者消费者问题实例

问题描述

生产者和消费者共享一个固定大小的缓冲区。生产者负责生产数据放入缓冲区,消费者负责消费数据。需解决缓冲区满时生产者的等待以及缓冲区空时消费者的等待问题。

实现代码(C语言,使用POSIX线程库)

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

#define BUFFER_SIZE 10
#define NUM_PRODUCERS 2
#define NUM_CONSUMERS 2

int buffer[BUFFER_SIZE];
int in = 0, out = 0;
pthread_mutex_t mutex;
pthread_cond_t not_full, not_empty;

void *producer(void *arg) {
    int data;
    for (;;) {
        data = rand() % 100;
        pthread_mutex_lock(&mutex);
        while (in - out == BUFFER_SIZE) {
            pthread_cond_wait(&not_full, &mutex); // 缓冲区满,等待
        }
        buffer[in % BUFFER_SIZE] = data;
        printf("Produced: %d\n", data);
        in++;
        pthread_cond_signal(&not_empty); // 唤醒消费者
        pthread_mutex_unlock(&mutex);
        usleep(rand() % 1000000); // 模拟生产间隔
    }
    return NULL;
}

void *consumer(void *arg) {
    for (;;) {
        pthread_mutex_lock(&mutex);
        while (in - out == 0) {
            pthread_cond_wait(&not_empty, &mutex); // 缓冲区空,等待
        }
        int data = buffer[out % BUFFER_SIZE];
        printf("Consumed: %d\n", data);
        out++;
        pthread_cond_signal(&not_full); // 唤醒生产者
        pthread_mutex_unlock(&mutex);
        usleep(rand() % 1000000); // 模拟消费间隔
    }
    return NULL;
}

int main() {
    pthread_t producers[NUM_PRODUCERS], consumers[NUM_CONSUMERS];

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&not_full, NULL);
    pthread_cond_init(&not_empty, NULL);

    for (int i = 0; i < NUM_PRODUCERS; ++i) {
        pthread_create(&producers[i], NULL, producer, NULL);
    }
    for (int i = 0; i < NUM_CONSUMERS; ++i) {
        pthread_create(&consumers[i], NULL, consumer, NULL);
    }

    // 理论上应等待所有线程结束,此处简化处理
    sleep(10); // 运行一段时间后手动结束

    for (int i = 0; i < NUM_PRODUCERS; ++i) {
        pthread_join(producers[i], NULL);
    }
    for (int i = 0; i < NUM_CONSUMERS; ++i) {
        pthread_join(consumers[i], NULL);
    }

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&not_full);
    pthread_cond_destroy(&not_empty);

    return 0;
}

解释

  • 使用pthread_mutex_lock()pthread_mutex_unlock()来控制对缓冲区的独占访问。
  • 当缓冲区满时,生产者调用pthread_cond_wait()not_full条件变量上等待,直到消费者消费数据后通过pthread_cond_signal()唤醒。
  • 类似地,消费者在缓冲区空时等待在not_empty条件变量上,由生产者完成填充后唤醒。
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
中文完整版的Java并发编程实践PDF电子书 作者:Brian Gogetz Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes Doug Lea 译者:韩锴 方秒 目录 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 线程的风险 1.4 线程无处不在 第1部分 基础 第2章 线程安全 2.1 什么是线程安全性 2.2 原子性 2.3 锁 2.4 用锁来保护状态 2.5 活跃度与性能 第3章 共享对象 3.1 可见性 3.2 发布和逸出 3.3 线程封闭 3.4 不可变性 3.5 安全发布 . 第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程安全类添加功能 4.5 同步策略的文档化 第5章 构建块 5.1 同步容器 5.2 发容器 5.3 阻塞队列和生产者一消费者模式 5.4 阻塞和可中断的方法 5.5 synchronizer 5.6 为计算结果建立高效、可伸缩的高速缓存 第2部分 构建并发应用程序 第6章 任务执行 6.1 在线程中执行任务 6.2 executor 框架 6.3 寻找可强化的并行性 第7章 取消和关闭 7.1 任务取消 7.2 停止基于线程的服务 7.3 处理反常的线程终止 7.4 jvm关闭 第8章 应用线程池 8.1 任务与执行策略问的隐性耦合 8.2 定制线程池的大小 8.3 配置threadpoolexecutor 8.4 扩展threadpoolexecutor 8.5 并行递归算法 第9章 gui应用程序 9.1 为什么gui是单线程化的 9.2 短期的gui任务 9.3 耗时gui任务 9.4 共享数据模型 9.5 其他形式的单线程子系统 第3部分 活跃度,性能和测试 第10章 避免活跃度危险 第11章 性能和可伸缩性 第12章 测试并发程序 第4部分 高级主题 第13章 显示锁 第14章 构建自定义的同步工具 第15章 原子变量与非阻塞同步机制 第16章 java存储模型
随着多核处理器的普及,使用并发成为构建高性能应用程序的关键。Java 5以及6在开发并发程序取得了显著的进步,提高了Java虚拟机的性能,提高了并发类的可伸缩性,并加入了丰富的新并发构建块。在本书中,这些便利工具的创造者不仅解释了它们究竟如何工作、如何使用,同时,还阐释了创造它们的原因,及其背后的设计模式。 本书既能够成为读者的理论支持,又可以作为构建可靠的,可伸缩的,可维护的并发程序的技术支持。本书并不仅仅提供并发API的清单及其机制,本书还提供了设计原则,模式和思想模型,使我们能够更好地构建正确的,性能良好的并发程序。 本书的读者是那些具有一定Java编程经验的程序员、希望了解Java SE 5,6在线程技术上的改进和新特性的程序员,以及Java和并发编程的爱好者。 目录 代码清单 序 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 线程的风险 1.4 线程无处不在 第1部分 基础 第2章 线程安全 2.1 什么是线程安全性 2.2 原子性 2.3 锁 2.4 用锁来保护状态 2.5 活跃度与性能 第3章 共享对象 3.1 可见性 3.2 发布和逸出 3.3 线程封闭 3.4 不可变性 3.5 安全发布 . 第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程安全类添加功能 4.5 同步策略的文档化 第5章 构建块 5.1 同步容器 5.2 发容器 5.3 阻塞队列和生产者一消费者模式 5.4 阻塞和可中断的方法 5.5 Synchronizer 5.6 为计算结果建立高效、可伸缩的高速缓存 第2部分 构建并发应用程序 第6章 任务执行 6.1 在线程中执行任务 6.2 Executor 框架 6.3 寻找可强化的并行性 第7章 取消和关闭 7.1 任务取消 7.2 停止基于线程的服务 7.3 处理反常的线程终止 7.4 JVM关闭 第8章 应用线程池 8.1 任务与执行策略问的隐性耦合 8.2 定制线程池的大小 8.3 配置ThreadPoolExecutor 8.4 扩展ThreadPoolExecutor 8.5 并行递归算法 第9章 GUI应用程序 9.1 为什么GUI是单线程化的 9.2 短期的GUI任务 9.3 耗时GUI任务 9.4 共享数据模型 9.5 其他形式的单线程子系统 第3部分 活跃度,性能和测试 第10章 避免活跃度危险 第11章 性能和可伸缩性 第12章 测试并发程序 第4部分 高级主题 第13章 显示锁 第14章 构建自定义的同步工具 第15章 原子变量与非阻塞同步机制 第16章 Java存储模型 附录A 同步Annotation 参考文献 索引

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值