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日

相关文章

  • 实现PHP多线程异步请求的3种方法

    以下是详细讲解“实现PHP多线程异步请求的3种方法”的完整攻略: 简介 在现代Web应用程序中,异步请求变得越来越流行,它可以显着提高应用程序的性能和响应速度。PHP作为一种流行的服务器端语言,也需要实现异步请求。本文将介绍三种实现PHP多线程异步请求的方法,并提供示例说明。 方法1:pcntl扩展 pcntl扩展是一个PHP扩展,旨在提供进程控制功能,其中…

    多线程 2023年5月16日
    00
  • Python Socket多线程并发原理及实现

    下面我将详细讲解“Python Socket多线程并发原理及实现”的完整攻略。 一、Python Socket多线程并发原理 Python Socket多线程并发原理主要是基于Python多线程技术和Socket通信原理。其中,Python多线程技术是用于多个客户端并发访问的依据,而Socket通信原理则是实现多客户端与服务端之间的通信。 具体来说,Pyth…

    多线程 2023年5月16日
    00
  • Redis分布式缓存与秒杀

    Redis分布式缓存与秒杀攻略 什么是Redis分布式缓存 Redis是一款基于内存的键值型数据库,具有高性能、高可用、易扩展等优点。而Redis分布式缓存是利用Redis进行分布式缓存实现,可以有效的解决高并发环境下的性能问题。 Redis分布式缓存的主要原理是将缓存数据分散到多个Redis单节点服务器上,通过Hash算法分配到不同的节点,从而实现负载均衡…

    多线程 2023年5月17日
    00
  • C/C++ 多线程的学习心得总结

    C/C++ 多线程的学习心得总结 为什么要学习多线程 多线程技术可以大大提高程序的效率和响应速度,特别是在处理大数据量、复杂运算和网络通信等场景中,开启多线程可以让程序更快地完成任务,同时还可以提高CPU的利用率。 同时,在面试中,多线程也是一个非常重要的考察点,具备多线程技能的程序员也更加受市场欢迎和青睐。 学习多线程的基础知识 在学习多线程之前,我们需要…

    多线程 2023年5月17日
    00
  • springboot tomcat最大线程数与最大连接数解析

    下面是“Spring Boot Tomcat最大线程数与最大连接数解析”的攻略。 一、Tomcat的最大连接数和最大线程数是什么? Tomcat是一个Web服务器,默认情况下,它的连接请求都是使用HTTP/1.1协议的。Tomcat的最大连接数指的是能同时建立的最大连接数,而Tomcat的最大线程数指的是Tomcat处理请求的最大线程数量。这两个参数可以决定…

    多线程 2023年5月17日
    00
  • Java并发编程之Executors类详解

    Java并发编程之Executors类详解 前言 在Java并发编程中,Executor Framework是一个非常重要的工具,可以帮助我们完成任务的管理、创建、调度和执行。Executors类是Executor Framework中的一个核心类,主要用于创建不同类型的Executor。 在本篇攻略中,我们将详细讲解Executors类的使用方法和相关注意…

    多线程 2023年5月17日
    00
  • Nodejs爬虫进阶教程之异步并发控制

    “Nodejs爬虫进阶教程之异步并发控制”是一个涉及到JavaScript异步编程和并发控制的进阶主题,下面详细讲解完整攻略: 什么是异步编程? 在Javascript中,异步编程是通过回调函数(callback)的方式来实现的。在异步操作完成后,将会调用回调函数来传递返回值或者错误信息。异步编程的好处是在处理耗时操作时不会阻塞主线程,从而提高了程序的响应速…

    多线程 2023年5月17日
    00
  • SpringBoot中使用多线程的方法示例

    下面我将为你详细讲解“SpringBoot中使用多线程的方法示例”的完整攻略。 概述 在SpringBoot中使用多线程可以提高系统的并发能力和处理效率。目前,Java中实现多线程的方式主要有两种:继承Thread类和实现Runnable接口。SpringBoot也提供了一些便利的方式来实现多线程操作,本文将介绍如何在SpringBoot中使用多线程的方法。…

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