linux多线程编程详解教程(线程通过信号量实现通信代码)

Linux多线程编程是现代操作系统最基本、也是最重要的部分之一。在实际应用开发中,多线程编程可以优化程序的性能,提高代码运行效率。本文将详细介绍如何通过信号量实现线程之间的通信,包含完整的代码示例。

一、什么是信号量?

信号量是一种用于多线程同步互斥的机制,用来协调进程对共享资源的访问。信号量是一个计数器,用来记录一个共享资源的数量,当某个进程需要使用该资源时,它需要先获取该资源对应的信号量,获得信号量后才可以访问该资源,当进程结束对该资源的使用后,它将释放该资源对应的信号量。

二、线程的通信方式

线程间的通信方式有很多种,如共享内存、管道、消息队列等。本文将重点介绍基于信号量的线程通信方式。

线程通信方式的基本思路如下:

  1. 线程A通过获取信号量S1来获得对资源R1的访问权。

  2. 线程B通过获取信号量S2来获得对资源R2的访问权。

  3. 线程A获取到S1信号量后,开始对资源R1进行访问操作。

  4. 线程B获取到S2信号量后,开始对资源R2进行访问操作。

  5. 当线程A访问操作完成后,释放S1信号量;

  6. 当线程B访问操作完成后,释放S2信号量。

这样就实现了线程之间的通信。

三、线程通过信号量实现通信的代码实现

下面是基于信号量的线程通信代码实现,包含两个示例:

示例1:生产者-消费者模型

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

#define BUFF_SIZE 5
sem_t mutex, full, empty;

int buffer[BUFF_SIZE];
int iHead = 0, iTail = 0;

void* producer(void* arg) {
  int item;
  while(1) {
    item = rand()%10;
    sem_wait(&empty);
    sem_wait(&mutex);
    buffer[iTail] = item;
    printf("producer produce item: %d\n", item);
    iTail = (iTail+1) % BUFF_SIZE;
    sem_post(&mutex);
    sem_post(&full);
    sleep(1);
  }
}

void* consumer(void* arg) {
  int item;
  while(1) {
    sem_wait(&full);
    sem_wait(&mutex);
    item = buffer[iHead];
    printf("consumer consume item: %d\n", item);
    iHead = (iHead+1) % BUFF_SIZE;
    sem_post(&mutex);
    sem_post(&empty);
    sleep(1);
  }
}

int main() {
  pthread_t tid1, tid2;
  sem_init(&mutex, 0, 1);
  sem_init(&full, 0, 0);
  sem_init(&empty, 0, BUFF_SIZE);
  pthread_create(&tid1, NULL, producer, NULL);
  pthread_create(&tid2, NULL, consumer, NULL);
  pthread_join(tid1, NULL);
  pthread_join(tid2, NULL);
  sem_destroy(&mutex);
  sem_destroy(&full);
  sem_destroy(&empty);
  return 0;
}

代码中,生产者线程通过sem_wait函数降低empty信号量的值,意味着资源队列中增加了一个资源;然后通过sem_wait函数降低mutex信号量的值,意味着其获得了对资源队列的独占访问权;将产生的资源添加到队列中,按照队列FIFO(先进先出)的原则,采用循环数组的方式对队列进行更新,将iTial指针向后移动;最后通过sem_post函数增加mutex信号量和full信号量的值,表示生产者完成生产,生产出的资源能够被消费者使用。

消费者线程通过sem_wait函数降低full信号量的值,意味着资源已经被生产者放置在了队列中;由于full>=1,因此才执行下面的sem_wait函数降低mutex信号量的值,表示对资源的独占使用权;消费者从共享队列中获取一个资源后,将队列的头指针向后移动,由于消耗了一个资源,通过sem_post函数增加mutex信号量和empty信号量的值,表示消费者完成了资源的消耗。

示例2:读者-写者模型

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

#define READ_THREAD_NUM 5
#define WRITE_THREAD_NUM 2

sem_t rwt, readMutex, writeMutex;
int data = 0;
int readerCount = 0;

void* reader(void* arg) {
  int id = *(int*)arg;
  while(1) {
    sem_wait(&rwt);   //请求对资源的读取
    sem_wait(&readMutex); //请求对读取者数量的独占访问
    readerCount++;
    if(readerCount == 1) {
      sem_wait(&writeMutex); //请求对资源的独占访问
    }
    sem_post(&readMutex);  //放弃对读取者数量的独占访问
    sem_post(&rwt);   //放弃对资源的读取
    printf("reader %d read data %d\n", id, data);
    sem_wait(&readMutex);
    readerCount--;
    if(readerCount == 0) {
      sem_post(&writeMutex); //放弃对资源的独占访问
    }
    sem_post(&readMutex);
    sleep(1);
  }
}

void* writer(void* arg) {
  int id = *(int*)arg;
  while(1) {
    sem_wait(&writeMutex);  //请求对资源的独占访问
    data++;
    printf("writer %d write data %d\n", id, data);
    sem_post(&writeMutex);  //放弃对资源的独占访问
    sleep(1);
  }
}

int main() {
  pthread_t readTid[READ_THREAD_NUM], writeTid[WRITE_THREAD_NUM];
  sem_init(&rwt, 0, 1);
  sem_init(&readMutex, 0, 1);
  sem_init(&writeMutex, 0, 1);
  int id[READ_THREAD_NUM+WRITE_THREAD_NUM];
  for(int i=0; i<READ_THREAD_NUM; i++) {
    id[i] = i;
    pthread_create(&readTid[i], NULL, reader, (void*)&id[i]);
  }
  for(int i=0; i<WRITE_THREAD_NUM; i++) {
    id[i+READ_THREAD_NUM] = i;
    pthread_create(&writeTid[i], NULL, writer, (void*)&id[i+READ_THREAD_NUM]);
  }

  for(int i=0; i<READ_THREAD_NUM; i++) {
    pthread_join(readTid[i], NULL);
  }
  for(int i=0; i<WRITE_THREAD_NUM; i++) {
    pthread_join(writeTid[i], NULL);
  }

  sem_destroy(&rwt);
  sem_destroy(&readMutex);
  sem_destroy(&writeMutex);

  return 0;
}

代码中,读者线程使用sem_wait函数对rwt进行降值操作, 获得对共享资源的读取权力;同时请求对readMutex进行独占访问,用来更新读取者的个数;如果读取者个数为1,则请求对共享资源的独占访问权(通过sem_wait函数),此时就可以阻止写者使用共享资源,防止产生冲突并保护数据一致性。获得共享资源的读取权力和读取个数的独占访问权后,该线程开始进行读取共享变量的操作,读取完成后释放对readMutex的独占访问权,同时请求对readMutex进行降值操作,用来更新读取者的个数;如果当前读取者个数为0,则表示一定没有其他读者在使用共享资源,通过sem_post函数释放对共享资源的独占访问权限(此说明中的独占访问权限类似于进程的 PV 操作)。写者线程同理。

以上就是无锁多线程编程中,通过信号量实现线程之间的通信方式的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:linux多线程编程详解教程(线程通过信号量实现通信代码) - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • JAVA多线程线程安全性基础

    关于JAVA多线程线程安全性,我给您讲一下我的理解。 什么是线程安全性? 在多线程开发中,往往有多个线程同时访问同一个共享资源,这时候就需要考虑线程安全性问题。当多个线程同时访问某一个对象时,如果不加以协调导致操作结果被破坏,则称为线程不安全。而当多个线程访问某一个对象时,不管运行时环境采用何种调度方式或者这些计算机内核以什么顺序来执行线程,而且在主调代码中…

    多线程 2023年5月17日
    00
  • Promise面试题详解之控制并发

    控制并发是 Promise 中比较重要、也比较常见的使用场景之一。 那么在面试中可能会有关于此方面的题目,下面我们来详细讲解一下控制并发的面试题攻略。 什么是并发控制? 并发控制指的是对于某些需要进行并发处理的操作,保证其并发数量的控制。 举个例子,假设我们现在需要爬取若干个网页,但是为了对目标网站造成压力使用单线程轮流爬取的策略并不可取,这时我们就可以用 …

    多线程 2023年5月16日
    00
  • 浅谈Swoole并发编程的魅力

    浅谈Swoole并发编程的魅力 Swoole是一个基于PHP编写的异步、并行、高性能网络通信引擎。通过使用Swoole,我们可以轻松地实现并发编程,提高应用程序的性能和稳定性。 Swoole的优势 相较于传统的PHP,Swoole的优势主要体现在以下几个方面: 高性能:传统的PHP应用一般采用阻塞I/O模型,每个请求都需要单独开启一个线程或进程进行处理。而S…

    多线程 2023年5月16日
    00
  • 在Go中构建并发TCP服务器

    针对“在Go中构建并发TCP服务器”的完整攻略,我为您提供以下内容: 1. 概述 在Go语言中,可以使用标准库net和net/http来轻松地构建TCP和HTTP服务器。在本文中,我们将介绍如何使用net库来构建并发TCP服务器。下面,将逐步介绍TCP服务器的实现步骤。 2. 步骤 步骤1:导入必要的包 既然我们要使用Go语言中的net库,因此在首个步骤中,…

    多线程 2023年5月17日
    00
  • Java多线程之线程状态的迁移详解

    Java多线程之线程状态的迁移详解 前言 在Java中,线程是一种轻量级的进程,它可以在一段程序中同时执行多条指令。线程的状态随着执行过程中不断发生变化,本文将详细介绍线程状态的迁移,从而让读者更好地理解线程的运行机制。 线程状态 Java线程的状态可以分为以下几种: 新建状态(New): 当Java线程还没有启动时,它的状态是New。 运行状态(Runna…

    多线程 2023年5月17日
    00
  • MySQL事务的ACID特性以及并发问题方案

    MySQL事务的ACID特性和并发问题方案是数据库设计中非常重要的话题。下面我将详细解释ACID特性以及如何解决并发问题,同时提供两个示例说明。 ACID特性 ACID是指数据库事务所需满足的四个特性: 原子性:事务是一个原子操作,要么全部执行,要么全部不执行。 一致性:事务执行前后,数据库中的数据必须保持一致状态。 隔离性:事务在执行时,不受其他事务的干扰…

    多线程 2023年5月16日
    00
  • JavaScript/TypeScript 实现并发请求控制的示例代码

    首先,实现并发请求控制的核心是利用 Promise 和 async/await 特性,统计当前请求并发数和控制请求的执行顺序。以下是一个 JavaScript 的示例代码: const MAX_REQUESTS = 5 // 设置最大并发请求数量 let currentRequest = 0 // 当前请求并发数计数器 // 请求响应函数,返回 Promis…

    多线程 2023年5月16日
    00
  • Python多线程编程入门详解

    Python多线程编程入门详解 什么是多线程编程? 多线程编程是指利用计算机CPU多核心,同时执行多个线程完成任务的编程方式。在Python中,多线程编程可以提高程序的运行效率,使得程序可以同时执行多个任务。 Python多线程编程的基本概念 在Python中,使用threading库可以进行多线程编程。在进行多线程编程时,需要注意以下概念: 线程:是程序执…

    多线程 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部