信号量

Linux-0.11操作系统实验6-地址映射与共享

最后都变了- 提交于 2020-02-07 02:37:35
实验环境: 地址映射与共享 实验理论: Linux-0.11操作系统实验6理论-地址映射与共享 实验任务: 用 Bochs 调试工具跟踪 Linux 0.11 的地址翻译(地址映射)过程,了解 IA-32 和 Linux 0.11 的内存管理机制; 在 Ubuntu 上编写多进程的生产者—消费者程序,用共享内存做缓冲区; 在信号量实验的基础上,为 Linux 0.11 增加共享内存功能,并将生产者—消费者程序移植到 Linux 0.11。 跟踪地址翻译过程 这节实验的目的是用 Bochs 的调试功能获取变量的虚拟地址映射的物理地址。实验过程跟着实验楼的描述进行即可。此处简单记录需要注意的几点: 根据实验中变量 i 保存在 ds:0x3004 这个地址,通过查询6.3段表,注意要使用自己本机实验环境的LDT表的物理地址: 实验楼中数据: “0x a2d0 0068 0x000082 fa ” 将其中的加粗数字组合为“0x00faa2d0”,这就是 LDT 表的物理地址 本机实验环境数据: 得到线性地址为 0x10003004 后,接下来通过页表将线性地址映射到物理地址,注意要使用自己本机实验环境的页框号,得到变量i的物理地址: 实验楼中数据: 线性地址 0x10003004 对应的物理页框号为 0x00fa7,和页内偏移 0x004 接到一起,得到 0x00fa7004,这就是变量

操作系统-信号量

隐身守侯 提交于 2020-02-05 03:37:18
信号量 信号量机制是一种功能较强的机制,可用于解决互斥和同步的问题,它只能被两个标准的 原语 wait(S)和signal(S)访问,也可以记为“P操作”和“V操作”。 原语:指完成某种功能且不被分割,不被中断执行的操作序列,通常可由硬件来实现。例如TestAndSet和Swap指令就是ongoing硬件实现的原子操作。原语功能的不被中断执行特性在单处理机上可由屏蔽中断方法来实现。 1、整型信息量 整型信号量被定义为一个表示资源数量的整型量S,wait和signal操作可描述为 wait ( S ) { while ( S <= 0 ) ; S = S - 1 ; } signal ( S ) { S = S + 1 ; } wait操作中,只要信号量S<=0,就会不断地测试。因此,该机制并未遵循“让权等待”,而是使进程处于忙等状态。 2、记录型信号量 记录型信号是不存在“忙等”现象的进程同步机制。 除需要一个用于代表资源数目的整型变量外,再层架一个进程链表L,用于连接所有等待该资源的进程。 记录型信号量可描述为 typedef struct { int value; struct process * L ; } semaphore ; 相应的wait(S)和signal(S)的操作如下 : void wait ( semaphore S ) { S . value -- ; if

Linux-0.11操作系统实验5-信号量的实现和应用

天大地大妈咪最大 提交于 2020-02-04 14:35:29
实验环境: 信号量的实现和应用 实验任务: 在 Ubuntu 下编写程序,用信号量解决生产者——消费者问题; 在 linux-0.11 中实现信号量,用生产者—消费者程序检验之。 用信号量解决生产者—消费者问题 实验要求: pc.c 程序需打开一个文件 buffer.txt 作为共享缓冲区,缓冲区同时最多只能保存 10 个数;创建一个生产者进程和N个消费者进程,其中生产者进程向缓冲区写入连续的整数,0,1,2,……,M,M>=500;消费者进程从缓冲区依次读取数字,每次读一个,并将读出的数字从缓冲区删除,然后将本进程 ID 和数字输出到标准输出。 为什么要有信号量? 对于生产者 来说,当缓冲区满,也就是空闲缓冲区个数为0时,此时生产者不能继续向缓冲区写数,必须等待,直到有消费者从满缓冲区取走数后,再次有了空闲缓冲区,生产者才能向缓冲区写数。 对于消费者 来说,当缓冲区空时,此时没有数可以被取走,消费者必须等待,直到有生产者向缓冲区写数后,消费者才能取数。并且如果当缓冲区空时,先后有多个消费者均想从缓冲区取数,那么它们均需要等待,此时需要记录下等待的消费者的个数,以便缓冲区有数可取后,能将所有等待的消费者唤醒,确保请求取数的消费者最终都能取到数。 也就是说,当多个进程需要协同合作时,需要根据某个信息,判断当前进程是否需要停下来等待;同时,其他进程需要根据这个信息判断是否有进程在等待

django信号量

女生的网名这么多〃 提交于 2020-02-04 11:37:52
django进行增删时候都会发出一个信号量 #在apps.py中添加 def ready(self)的方法 class UserOperationConfig(AppConfig): name = 'user_operation' verbose_name = "用户操作管理" def ready(self): import user_operation.signals #新建signals.py from django.db.models.signals import post_save, post_delete from django.dispatch import receiver from rest_framework.authtoken.models import Token from django.contrib.auth import get_user_model from user_operation.models import UserFav @receiver(post_save, sender=UserFav) def create_userfav(sender, instance=None, created=False, **kwargs): if created: goods = instance.goods goods.fav_num += 1

linux之间进程通信

扶醉桌前 提交于 2020-02-02 00:17:47
进程间通信方式: 同主机进程间数据交换机制: pipe(无名管道) / fifo(有名管道)/ message queue(消息队列)和共享内存。 必备基础: fork() 创建一个与之前完全一样的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都 复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。    vfork : 与fork用法相同,但是他和父进程共享同样的数据存储,因此无需完全复制父进程的地址空间。 // fork() study example 1#include <unistd.h> #include <stdio.h> int main () { pid_t fpid; //fpid表示fork函数返回的值 int count=0; // fork 会将这个变量存在两个不同的内存中,所以两次count的值都是 1 ,而不是 1,2 。 fpid=fork(); if (fpid < 0) printf("error in fork!"); else if (fpid == 0) { printf("i am the child process, my process id is %d、n",getpid(

进程间通信

与世无争的帅哥 提交于 2020-01-30 11:34:38
进程间通信原因 因为每一个进程都是拥有一个独立的虚拟地址空间的,促使进程独立,导致了进程之间需要协作。 进程间通信分为 数据传输-----管道,消息队列 数据共享-----共享内存 进程控制-----信号量 首先先谈谈管道和共享内存 管道 ---匿名管道,命名管道 本质:管道其实就是一块内存,是内核当中的缓冲区 匿名管道---没有标识 特性: 具有亲缘关系的进程间通信 半双工,数据只能有一个流向 提供字节流服务 自带同步与互斥功能 生命周期随进程,进程终止,生命周期消失 如果管道为空,则读阻塞 如果管道为满,则写阻塞 如果管道的读端被关闭,则写端往管道当中写数据的时候,会造成管道破裂,并且导致进程收到SIGPIPE信号,从而进程终止 如果管道的写端被关闭掉了,则读端读完管道的数据之后,read不会陷入阻塞状态,而是返回。执行代码剩下的正常流程 管道大小PIPE_SIZE:64K,PIPE_BUG:4K 如果写入的数据大于PIPE_BUG的话,则不保证写入数据的原子性 原子性:当前操作不被打断,换句话说,在管道的读写操作是不可以被打断的 临界资源:同一时间,当前资源只能被一个进程所访问 互斥:同一时间,保证只能有一个进程访问临界资源 同步:保证临界资源访问的合理性 创建一个管道(亲缘关系的进程中使用) int pipe(int pipefd[2]); pipefd[0]

同步基元概述

◇◆丶佛笑我妖孽 提交于 2020-01-30 07:10:55
NET Framework 提供了一系列同步基元来控制线程交互并避免争用条件。这可大致分为三个类别:锁定、通知和联锁操作。 上述类别的定义并非是绝对的:有些同步机制具有多个类别的特征;一次释放一个线程的事件的功能类似于锁定;任何锁定的释放都可看作一个信号;而联锁操作可用于构造锁定。但是,这些类别仍然是有用的。 记住线程同步是协作这一点非常重要。只要有一个线程避开同步机制直接访问受保护的资源,该同步机制就不是有效的。 锁定 锁向一个线程一次提供一个资源的控制功能,或者向指定数目的线程提供此功能。请求正在使用中的独占锁的线程会被阻止,直到该锁变为可用为止。 独占锁 锁定的最简单的形式是 C# 的 lock 语句(在 Visual Basic 中为 SyncLock ),该语句可控制对代码块的访问。这种块通常称为临界区。 lock 语句使通过使用 Monitor 类的 Enter 和 Exit 方法实现的,它使用 try…catch…finally 确保该锁被释放。 通常情况下,使用 lock 语句保护小代码块并且不跨越多个方法是使用 Monitor 类的最佳方法。 Monitor 类功能强大,但是容易形成孤立锁和死锁。 Monitor 类 Monitor 类提供了附加功能,可结合 lock 语句使用: TryEnter 方法允许当前被阻止,正在等待资源的线程在指定时间间隔之后放弃

FreeRTOS专栏12:二值信号量

ε祈祈猫儿з 提交于 2020-01-30 01:22:31
信号量 1 信号量用于共享资源的访问: 2 信号量用于任务同步: 为什么一直说在中断服务函数中,不能够做太多的事情? 在进入中断服务函数时,低优先级的中断就不能响应,同类型的中断也无法响应,所以就要求ISR一定要短,快进快出。 最好的解决方案时,在中断服务函数中发送一个信号量,在任务中等待信号量,实现任务同步。 二值信号量 二值信号量简介: 二值信号量其实就是一个只有一个队列项的队列,这个特殊的队列要么是满的,要么是空的,这不正好就是二值的吗? 任务和中断使用这个特殊队列不用在乎队列中存的是什么消息,只需要知道这个队列是满的还是空的。可以利用这个机制来完成任务与中断之间的同步。 二值信号量执行流程: 创建信号量: 动态创建二值信号量: 实际上,信号量就是通过队列来实现的,源码如下: #define semSEMAPHORE_QUEUE_ITEM_LENGTH ((uint8_t)0U) #if (configSUPPORT_DYNAMIC_ALLOCATION == 1) #define xSemaphoreCreateBinary() xQueueGenericCreate((UBaseType_t)1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE) #endif 实际上,就是调用创建队列的函数

#Linux#进程间通信# 信号量(semophore)

偶尔善良 提交于 2020-01-28 08:21:39
信号量本质上是一个计数器( 不设置全局变量是因为进程间是相互独立的,而这不一定能看到,看到也不能保证++引用计数为原子操作 ),可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。主要作为进程间以及同一进程内不同线程之间的同步和互斥手段。 它和管道有所不同,它不以传送数据为主要目的,它主要是用来保护共享资源(信号量也属于临界资源),使得资源在一个时刻只有一个进程独享。 信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被 并发 调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。 信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域

Java 信号量 Semaphore

邮差的信 提交于 2020-01-27 21:58:49
public static void main(String[] args) { // 线程池 ExecutorService exec = Executors.newCachedThreadPool(); // 只能5个线程同时访问 final Semaphore semp = new Semaphore(5); // 模拟20个客户端访问 for (int index = 0; index < 20; index++) { final int NO = index; Runnable run = new Runnable() { public void run() { try { // 获取许可 semp.acquire(); System.out.println("Accessing: " + NO); Thread.sleep((long) (Math.random() * 10000)); // 访问完后,释放 semp.release(); System.out.println("-----------------"+semp.availablePermits()); } catch (InterruptedException e) { e.printStackTrace(); } } }; exec.execute(run); } // 退出线程池 exec