Linux中经典的并发编程问题生产者和消费者

一,进程和线程区别

1,进程是程序的一次执行实例,是系统进行资源分配和调度的独立单位。进程具有独立的内存空间、系统资源以及独立的执行序列。每个进程都有其独立的进程控制块(PCB),用于描述进程的状态和相关信息。

2,线程是进程中的一个执行单元,是操作系统进行运算调度的最小单元。线程共享进程的内存空间和系统资源,有自己的执行序列,但没有独立的内存空间。线程之间可以通过共享内存等方式进行通信和同步。

3,进程中包含了线程,线程属于进程。一个进程可以包含多个线程,而每个线程都是进程的一部分。

二,线程互斥,同步方式

在Linux中,线程的互斥(互斥量)和同步(如条件变量、信号量、读写锁等)是多线程编程中非常重要的概念。这些机制帮助开发者避免数据竞争、死锁和其他并发问题。以下是Linux中常用的线程互斥和同步方式:

1,互斥量(Mutex)
互斥量用于保护对共享资源的访问,以确保一次只有一个线程可以访问该资源
在C/C++中,通常使用pthread_mutex_t类型表示互斥量,并通过pthread_mutex_init、pthread_mutex_lock、pthread_mutex_unlock等函数来初始化、锁定和解锁互斥量。

2,条件变量(Condition Variable)
条件变量与互斥量一起使用,允许线程等待某个条件成立后再继续执行。
当某个条件不满足时,线程可以使用条件变量将自己阻塞,并在条件满足时被唤醒
在C/C++中,使用pthread_cond_t类型表示条件变量,并通过pthread_cond_init、pthread_cond_wait、pthread_cond_signal等函数来初始化、等待和发送信号。

3,信号量(Semaphore)
信号量是一种更通用的同步机制,可以用于控制多个线程对共享资源的访问。
与互斥量不同,信号量允许多个线程同时访问资源,但会限制同时访问的线程数。
在Linux中,可以使用POSIX信号量(sem_t)或System V信号量(struct sembuf、semid_ds等)。

4,读写锁(Read-Write Lock)
读写锁允许多个线程同时读取共享资源,但只允许一个线程写入
这对于读操作远多于写操作的场景非常有用,因为它可以提高并发性能。
在C/C++中,可以使用pthread_rwlock_t类型表示读写锁,并通过pthread_rwlock_init、pthread_rwlock_rdlock、pthread_rwlock_wrlock等函数来初始化、读锁定和写锁定。

5, 自旋锁(Spinlock)
自旋锁是一种特殊的互斥量,当线程尝试获取锁失败时,它会在一个循环中持续尝试获取锁,而不是被阻塞
自旋锁适用于短时间的等待场景,因为它避免了线程切换的开销。但是,如果等待时间较长,自旋锁会浪费CPU资源。
在Linux内核编程中,自旋锁是一个常见的同步机制。

以上就是在Linux中常用的线程互斥和同步方式。在实际应用中,应根据具体场景选择合适的同步机制。

三,生产者和消费者原理

在Linux中,生产者和消费者问题是一个经典的并发编程问题。它描述了两个或多个进程(或线程)共享一个固定大小的缓冲区,并且按照生产者-消费者模式进行交互。生产者负责生成数据并放入缓冲区,而消费者则从缓冲区中取出数据进行处理。

以下是生产者和消费者问题的基本原理以及使用POSIX线程(pthreads)的C语言实现代码:

基本原理

1,共享缓冲区:有一个固定大小的缓冲区用于存储数据。
2,互斥访问:生产者和消费者需要互斥地访问缓冲区,以避免数据竞争。
3,同步机制:使用条件变量、信号量或其他同步机制来确保生产者在缓冲区满时不会继续生产,消费者在缓冲区空时不会继续消费。

C语言实现

以下是一个简单的生产者和消费者问题的C语言实现,使用了POSIX线程、互斥锁和条件变量:

#include <stdio.h>  
#include <stdlib.h>  
#include <pthread.h>  
  
#define BUFFER_SIZE 10  
  
int buffer[BUFFER_SIZE];  
int in = 0;  
int out = 0;  
  
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  
pthread_cond_t not_full = PTHREAD_COND_INITIALIZER;  
pthread_cond_t not_empty = PTHREAD_COND_INITIALIZER;  
  
void *producer(void *arg) {  
    for (int i = 0; i < 100; ++i) {  
        pthread_mutex_lock(&mutex);  
        // 等待缓冲区不满  
        while ((in + 1) % BUFFER_SIZE == out) {  
            pthread_cond_wait(&not_full, &mutex);  
        }  
        // 生产数据  
        buffer[in] = i;  
        printf("Produced: %d\n", buffer[in]);  
        in = (in + 1) % BUFFER_SIZE;  
        pthread_cond_signal(&not_empty); // 通知消费者  
        pthread_mutex_unlock(&mutex);  
    }  
    pthread_exit(NULL);  
}  
  
void *consumer(void *arg) {  
    for (int i = 0; i < 100; ++i) {  
        pthread_mutex_lock(&mutex);  
        // 等待缓冲区不空  
        while (in == out) {  
            pthread_cond_wait(&not_empty, &mutex);  
        }  
        // 消费数据  
        int data = buffer[out];  
        printf("Consumed: %d\n", data);  
        out = (out + 1) % BUFFER_SIZE;  
        pthread_cond_signal(&not_full); // 通知生产者  
        pthread_mutex_unlock(&mutex);  
    }  
    pthread_exit(NULL);  
}  
  
int main() {  
    pthread_t prod, cons;  
    pthread_create(&prod, NULL, producer, NULL);  
    pthread_create(&cons, NULL, consumer, NULL);  
    pthread_join(prod, NULL);  
    pthread_join(cons, NULL);  
    return 0;  
}

在这个例子中,生产者和消费者都是无限循环的,但为了简化,我们限制了它们各自只生产或消费100个数据项。注意,在实际应用中,你可能需要设置更复杂的退出条件。

这个代码使用了互斥锁(pthread_mutex_t)来保护对缓冲区的访问,并使用条件变量(pthread_cond_t)来实现生产者和消费者之间的同步。当缓冲区满时,生产者会等待not_full条件变量;当缓冲区空时,消费者会等待not_empty条件变量。每次生产或消费一个数据项后,相应的条件变量会被触发,以通知等待的线程可以继续执行。

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤舟簔笠翁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值