线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。

Linux系统中的线程间通信方式主要以下几种:
锁机制:包括互斥锁、条件变量、读写锁、自旋锁
        互斥锁提供了以排他方式防止数据结构被并发修改的方法。互斥锁确保同一时间只能有一个线程访问共享资源。当锁被占用时试图对其加锁的线程都进入阻塞状态(释放CPU资源使其由运行状态进入等待状态)。当锁释放时哪个等待线程能获得该锁取决于内核的调度。

读写锁允许多个线程同时读共享数据,而对写操作是互斥的。当以写模式加锁而处于写状态时任何试图加锁的线程(不论是读或写)都阻塞,当以读状态模式加锁而处于读状态时“读”线程不阻塞,“写”线程阻塞。读模式共享,写模式互斥。

自旋锁上锁受阻时线程不阻塞而是在循环中轮询查看能否获得该锁,没有线程的切换因而没有切换开销,不过对CPU的霸占会导致CPU资源的浪费。 所以自旋锁适用于并行结构(多个处理器)或者适用于锁被持有时间短而不希望在线程切换产生开销的情况。

条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。这个主要是使用锁的机制实现,所以划到锁这个里面了。

信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
信号机制(Signal):类似进程间的信号处理

2. 具体实现

2.1 信号量机制

1. 简介
1.1信号量简介
Linux下主要分为两种信号量,system-v和posix信号量,posix信号量又分为无名信号量和有名信号量,这里我们只分享无名信号量这里我们主要研究posix信号量。信号量是同步的一种方式,常常用于对共享资源的访问,举一个常见的例子,假如一个停车场有100个停车位,我们将车停在这个停车场需要看一下这个停车场还有多少车位可以停,此时空位就是一个信号量,每空一个车位,信号量+1,每次停一辆车时信号量-1.

1.2 信号量特点
(1)信号量会使等待资源线程进入休眠状态,所以适合于那些占用资源比较久的场合,比较车倒车状态的切换。
(2)在驱动中,信号量不可以用于中断中,原因是信号量会引起休眠状态,中断不能休眠。
(3)若共享资源的持有时间比较短,则不适合使用信号量,频繁的休眠,切换线程会导致开销远远大于信号量所带来的那点优势。

2.相关操作函数API
2.1 初始化

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared,unsigned int value);
1
2
sem :信号量变量;
pshared:是否在多个进程中传递信号量,若不是则写为0;
value:该参数指定信号量的初始值。如果想要在两个进程之间使用信号量,需要确保sem参数指向两个进程之间共享的内存范围。

2.2 销毁

#include <semaphore.h>
int sem_destroy(sem_t *sem);
1
2
2.3 P操作

#include <semaphore.h>
int sem_trywait(sem_t *sem);
int sem_wait(sem_t *sem);
returns 0 on success; 
on error,-1 is returned, 
1
2
3
4
5
如果信号量的值大于0,则此时会将信号量的值减1,并且立刻返回,若当前信号量的值为0,那么sem_wait会导致线程阻塞,直到信号量的值大于0或者被信号中断才返回,而sem_trywait为非阻塞版本,当信号量为0时,该函数回-1并且将errno置为EAGAIN。

2.4 V操作

#include <semaphore.h>
int sem_post(sem_t *sem);
returns 0 on success;
on error,-1 is returned, 
1
2
3
4
该函数用于给信号量计数+1,若此时用sem_wait阻塞的线程则被唤醒。

2.5 取值操作

#include<semaphore.h>
int sem_t getvalue(sem_t sem, int *val);
returns 0 on success;
on error,-1 is returned, 
1
2
3
4
val返回的值

3.简单例子
#include <stdlib.h>
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>

sem_t g_sem;

void *ReadThreadFun(void *arg)
{
    while(1)
    {
        printf("read 1 begin\n");
        sem_wait(&g_sem);
        printf("read 1 end\n");
    }
}

void *WriteThreadFun(void *arg)
{
    while(1)
    {
        sleep(1);
        printf("write 1 begin\n");
        sem_post(&g_sem);
        printf("write 1 end\n");
    }
}

int main(int argc,char **argv)
{
    pthread_t pReadID;
    pthread_t pWriteID;
    int iRet;
    
    iRet = sem_init(&g_sem,0,0);
    if(iRet != 0)
    {
        printf("sem_init failed\n");
        return 0;
    }
    
    iRet = pthread_create(&pReadID,NULL,ReadThreadFun,NULL);
    if(iRet !=0 )
    {
        printf("ReadThreadFun create failed\n");
        return -1;
    }
    
    iRet = pthread_create(&pWriteID,NULL,WriteThreadFun,NULL);
    if(iRet !=0 )
    {
        printf("WriteThreadFun create failed\n");
        return -1;
    }
    
    pthread_join(pReadID,NULL);
    pthread_join(pWriteID,NULL);
    
    sem_destroy(&g_sem);
    
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
结果:

read 1 begin
write 1 begin
write 1 end
read 1 end
read 1 begin
write 1 begin
write 1 end
read 1 end
....
1
2
3
4
5
6
7
8
9
当read线程开始时,此时sem的值为0,阻塞此线程,write线程开始,此时sem的值变为0,解除线程阻塞
————————————————
版权声明:本文为CSDN博主「深海带鲤鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43824344/article/details/112147273

2.2

信号量机制有专门的函数直接告知wait等待的线程,然后等待线程操作数据结束

在这个例子中,线程C因调用了监控对象的wait()方法而挂起,线程D通过调用监控对象的notify()方法唤醒挂起的线程C。我们还可以看到,两个线程都是在同步块中调用的wait()和notify()方法。如果一个线程在没有获得对象锁的前提下调用了这个对象的wait()或notify()方法,方法调用时将会抛出 IllegalMonitorStateException异常。

注意,当一个线程调用一个对象的notify()方法,则会唤醒正在等待这个对象所有线程中的一个线程(唤醒的线程是随机的),当线程调用的是对象的notifyAll()方法,则会唤醒所有等待这个对象的线程(唤醒的所有线程中哪一个会执行也是不确定的)。

这里还有一个问题,既然调用对象wait()方法的线程需要获得这个对象的锁,那么这会不会阻塞其它线程调用这个对象的notify()方法呢?答案是不会阻塞,当一个线程调用监控对象的wait()方法时,它便会释放掉这个监控对象锁,以便让其它线程能够调用这个对象的notify()方法或者wait()方法。

另外,当一个线程被唤醒时不会立刻退出wait()方法,只有当调用notify()的线程退出它的同步块为止。也就是说,被唤醒的线程只有重新获得监控对象锁时才会退出wait()方法,因为wait()方法在同步块中,它的执行需要再次获得对象锁。所以,当通过notifyAll()方法唤醒被阻塞的线程时,一次只能有一个线程会退出wait()方法,同样是因为每个线程都需要先获得监控对象锁才能执行同步块中的wait()方法退出。

————————————————
版权声明:本文为CSDN博主「假装自己会Python」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_51958727/article/details/120456233

线程间通信 - 多线程编程(一)相关推荐

  1. 《JUC并发编程 - 基础篇》JUC概述 | Lock接口 | 线程间通信 | 多线程锁 | 集合线程安全

  2. Java多线程编程-(5)-使用Lock对象实现同步以及线程间通信

    前几篇: Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-线程本地Th ...

  3. Java多线程编程-(4)-线程间通信机制的介绍与使用

    上一篇: Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(3)-线程本地Th ...

  4. C++多线程编程分析-线程间通信

    上文我们介绍了如何建立一个简单的多线程程序,多线程之间不可避免的需要进行通信.相比于进程间通信来说,线程间通信无疑是相对比较简单的. 首先我们来看看最简单的方法,那就是使用全局变量(静态变量也可以)来 ...

  5. 【Java 并发编程】多线程、线程同步、死锁、线程间通信(生产者消费者模型)、可重入锁、线程池

    并发编程(Concurrent Programming) 进程(Process).线程(Thread).线程的串行 多线程 多线程的原理 多线程的优缺点 Java并发编程 默认线程 开启新线程 `Ru ...

  6. java多线程编程(六)-线程间通信

    一:线程通信介绍 线程通信是通过主动放弃对资源的使用,而让给其它线程的过程.合理的安排多个线程对同一资源的使用,即设计线程间的通信,可以完成很多复杂的任务. 二:线程通信实现 1,java.lang. ...

  7. Java多线程:线程间通信之Lock

    Java 5 之后,Java在内置关键字sychronized的基础上又增加了一个新的处理锁的方式,Lock类. 由于在Java线程间通信:volatile与sychronized中,我们已经详细的了 ...

  8. 线程间通信的几种方法_并发编程中的线程间通信

    线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 线程通信常用的方式有: wait/notify 等待 Volatile 内存共享 CountDownLatc ...

  9. Java 多线程(六)——进程间通信与线程间通信

    以前一直想找个机会总结一下进程和线程的通信机制,但由于技术和平台的局限性,一直没有找准切入点.由于马上要毕业了,对自己技术的总结和梳理的前提下写了本篇文章,如有错误之处,敬请拍砖和指教. 操作系统的主 ...

最新文章

  1. ASP.NET之间数据的传递(未完)
  2. ecshop简单三部实现导航分类二级菜单
  3. STM32使用TIM闪烁LED——输出比较方式
  4. poj 2421 Constructing Roads
  5. SDUT2389Ballot evaluation
  6. Spring Boot 多数据源(读写分离)入门
  7. java 参数 string_java(String和StringBuffer分别作为参数传递)
  8. 定义函数up(ch),如字符变量ch是小写字母就转换成大写字母并通过up返回,否则字符ch不改变。要求在短小而完全的程序中显示这个程序是怎样被调用的。
  9. java数组的声明学号姓名线性结构_20172302 《Java软件结构与数据结构》实验一:线性结构实验报告...
  10. php开启安全模式后影响的函数
  11. 大数据在银行的七个应用实例
  12. java多网卡组播,多网卡 组播
  13. oracle exadata X8,ORACLEEXADATA数据库云服务器X8.PDF
  14. android打印机字体大小,热敏打印机字体大小设置,怎么设置打印机字体
  15. 远程办公系统有哪些 给远程办公的几点建议
  16. 海思3518E开发笔记1.1——HI3518E方案整体架构介绍
  17. APM 飞控文档翻译1
  18. 对讲机技术术语中英文翻译对照表
  19. 将北斗卫星授时(GPS时钟系统)技术应用数据采集系统
  20. OCR之:Pytesseract端到端文字识别(包含源代码以及极为详细的解释)

热门文章

  1. Java运费计算程序_Woocommerce自定义字段的运费计算器
  2. 高逼格的——chirp
  3. DS18B20 FPGA
  4. 计算机技术与科学A类学校,全国第四轮学科评估结果(A+、A类学校)
  5. ppt文件转pdf文件转换器绿色版
  6. [mysql]-inception和archer安装
  7. 爱立信携手中国电信运用爱立信频谱共享技术
  8. 【Tomcat源码阅读】核心组件介绍(二)
  9. 【坑】python、R里面条件判断是不一样的
  10. openwrt无wan6口,如何设置ipv6