精华内容
下载资源
问答
  • Linux系统多进程并发信号量互斥机制 相关知识 相关函数内容 Linux系统信号量控制 实现代码 Process1.cpp #include <bits/stdc++.h> #include <unistd.h> #include <sys/ipc.h> #include <...

    Linux系统多进程并发信号量互斥机制

    相关知识

    实现代码

    • Process1.cpp
    #include <bits/stdc++.h>
    #include <unistd.h>
    #include <sys/ipc.h>
    #include <sys/types.h>
    #include <sys/sem.h>
    #include <sys/wait.h>
    using namespace std;
    
    const int TIMES = 5;
    const int DELAY = 5;
    
    const int KEY = 2048;
    
    union Semaphore {
        int value;
        semid_ds *buffer;
        unsigned short *array;
        seminfo *infomation;
    };
    
    static int semaphoreID = 0;
    
    static bool initializeSemaphoreValue() {
        Semaphore semaphoreUnion;
    
        semaphoreUnion.value = 1;
    
        return semctl(semaphoreID, 0, SETVAL, semaphoreUnion) == -1 ? false : true;
    }
    
    static bool semaphoreP() {
        sembuf semaphoreBuffer;
    
        semaphoreBuffer.sem_num = 0;
        semaphoreBuffer.sem_op = -1;
        semaphoreBuffer.sem_flg = SEM_UNDO;
    
        return semop(semaphoreID, &semaphoreBuffer, 1) == -1 ? false : true;
    }
    
    static bool semaphoreV() {
        sembuf semaphoreBuffer;
    
        semaphoreBuffer.sem_num = 0;
        semaphoreBuffer.sem_op = 1;
        semaphoreBuffer.sem_flg = SEM_UNDO;
    
        return semop(semaphoreID, &semaphoreBuffer, 1) == -1 ? false : true;
    }
    
    static void deleteSemaphoreSet() {
        Semaphore semaphoreUnion;
    
        if (semctl(semaphoreID, 0, IPC_RMID, semaphoreUnion) == -1) {
            fprintf(stderr, "Failed to delete semaphore\n");
        }
    }
    
    int main(int argc, char const *argv[])
    {
        if ((semaphoreID = semget((key_t) KEY, 1, 0666 | IPC_CREAT)) == -1) {
            fprintf(stderr, "Create semaphore set failed!\n");
            abort();
        }
    
        if (!initializeSemaphoreValue()) {
            fprintf(stderr, "Initialize semaphore failed!\n");
            abort();
        }
    
        srand((unsigned)getpid());
        string message = "Process1";
    
        for (int i = 0; i < TIMES; i++) {
            if (!semaphoreP()) {
                printf("Semaphore P failed!\n");
                abort();
            }
            cout << message <<endl;
            fflush(stdout);
            sleep(rand() % DELAY);
            if (!semaphoreV()) {
                printf("Semaphore V failed!\n");
                abort();
            }
        }
        return 0;
    }
    
    • Process2.cpp
    #include <bits/stdc++.h>
    #include <unistd.h>
    #include <sys/ipc.h>
    #include <sys/types.h>
    #include <sys/sem.h>
    #include <sys/wait.h>
    using namespace std;
    
    const int TIMES = 5;
    const int DELAY = 5;
    
    const int KEY = 2048;
    
    union Semaphore {
        int value;
        semid_ds *buffer;
        unsigned short *array;
        seminfo *infomation;
    };
    
    static int semaphoreID = 0;
    
    static bool initializeSemaphoreValue() {
        Semaphore semaphoreUnion;
    
        semaphoreUnion.value = 1;
    
        return semctl(semaphoreID, 0, SETVAL, semaphoreUnion) == -1 ? false : true;
    }
    
    static bool semaphoreP() {
        sembuf semaphoreBuffer;
    
        semaphoreBuffer.sem_num = 0;
        semaphoreBuffer.sem_op = -1;
        semaphoreBuffer.sem_flg = SEM_UNDO;
    
        return semop(semaphoreID, &semaphoreBuffer, 1) == -1 ? false : true;
    }
    
    static bool semaphoreV() {
        sembuf semaphoreBuffer;
    
        semaphoreBuffer.sem_num = 0;
        semaphoreBuffer.sem_op = 1;
        semaphoreBuffer.sem_flg = SEM_UNDO;
    
        return semop(semaphoreID, &semaphoreBuffer, 1) == -1 ? false : true;
    }
    
    static void deleteSemaphoreSet() {
        Semaphore semaphoreUnion;
    
        if (semctl(semaphoreID, 0, IPC_RMID, semaphoreUnion) == -1) {
            fprintf(stderr, "Failed to delete semaphore\n");
        }
    }
    
    int main(int argc, char const *argv[])
    {
        if ((semaphoreID = semget((key_t) KEY, 1, 0666 | IPC_CREAT)) == -1) {
            fprintf(stderr, "Create semaphore set failed!\n");
            abort();
        }
    
        if (!initializeSemaphoreValue()) {
            fprintf(stderr, "Initialize semaphore failed!\n");
            abort();
        }
    
        srand((unsigned)getpid());
        string message = "Process2";
        usleep(100);
        for (int i = 0; i < TIMES; i++) {
            if (!semaphoreP()) {
                printf("Semaphore P failed!\n");
                abort();
            }
            cout << message <<endl;
            fflush(stdout);
            sleep(rand() % DELAY);
            if (!semaphoreV()) {
                printf("Semaphore V failed!\n");
                abort();
            }
        }
        return 0;
    }
    
    

    输出结果

    Process1
    Process2
    Process1
    Process2
    Process1
    Process2
    Process1
    Process2
    Process1
    Process2
    

    编译

    上述实现使用了两个进程,而不是利用一个父进程再创建另一个子进程

    g++ Process1.cpp -o Process1
    g++ Process2.cpp -o Process2
    ./Process1 & ./Process2
    

    最后

    • 由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!
    展开全文
  • 并发互斥信号量

    2013-11-15 16:13:34
    并发互斥信号量 一、关键术语  1原子操作:一个或多个指令的序列,对外是不可分的;即没有其他进程可以看到其中间状态或者中断此操作。  2.临界区(critical section):是一段代码,在这段代码中进程将...

    并发:互斥与信号量

    一、关键术语

           1原子操作:一个或多个指令的序列,对外是不可分的;即没有其他进程可以看到其中间状态或者中断此操作。

           2.临界区(critical section):是一段代码,在这段代码中进程将访问资源;只能有一个进程在此段代码中运行。

           3.互斥(mutual exclusion):当一个进程在临界区访问共享资源时,其他进程不能进入临界区访问任何资源。

     

    二、互斥

           1.为什么要互斥:因为当多个进程同时运行在临界区对共享资源进行操作时,可能会导致得到非预期结果。

           2.互斥的实现

           2.1硬件方法

                  2.1.1 中断禁用

                         在单处理器机器中,并发进程只能串行执行,所以只要禁止对临界区的中断即可保证互斥。

           缺点:导致效率降低;不能用于多处理器机器。

                  2.1.2 专用机器指令

                         设计专门的指令,保证指令执行是原子的。

                  1).比较和交换指令

                         intcompare_and_swap(int &word, int testval, int newval)

                         {

                                intoldval=word;

                                if(old==testval)word=newval;

                                returnoldval;

                         }

                         compare_and_swap是机器指令,在执行期间不会被中断。

                         //***

                         while(compare_and_swap(a,0,1)==1);       //初始化a=0

                         //临界区

                         a=0;

                         //***

                         第一个进程执行时,a=0,指令返回0,所以进程进入临界区,然后a=1,其他进程无法进入临界区。

                  缺点:使用了忙等待,无法进入临界区的进程一直在执行指令,消耗CPU时间。

          

                  2.1.3 信号量(semaphore)

                         信号量是进程间传递信号的一个整数值。只能进行三种操作,初始化、递减和增加。

           1)一个信号量S可以被初始化为非负整数

           2)Wait(s)操作使S减1。如果S变成负数,则将执行Wait的进程阻塞,放进S的等待队列中。如果S为正,则继续执行(进入临界区)

           3)Signal(s)使S增加1。如果S小于等于0,则说明在S的等待队列中有进程被阻塞,所以将其中一个进程解除阻塞。

     

    开始时,S被初始化为正数,S等于能同时进入临界区的解除进程数,当进入临界区的进程数超过初始值后,执行Wait()的进程进入等待队列,并阻塞(避免了忙等待),S值小于0,其绝对值|s|等于等待队列中进程数。

     

    信号量的实现:

           因为信号量也是共享资源,对其操作也需要互斥,可以用cmp&swap实现。

    如:

    Wait(s)

    {

           while(compare_and_swap(s.flag,0,1)==1);  

           s.count--;

           if(s.count<0)

           {     //阻塞该进程 s.flag=0

           }

           s.flag=0;//让其他进程通过while

    }

    Signal类似。

    这里也需要忙等待,但是这里忙等待的对象是Wait和Signal,他们的操作相对于临界区来说很短,所以开销可以接受。

     

    总结:

           比如临界区C是厕所,信号量S表示同时能进厕所的人数。

    不使用信号量时:

    第一个人进入C后,其他人只能在外面等待,并且不断询问里面的人好了没。

     

    使用信号量:

          

    增加了房间S和B,要上厕所时,先到S里面那C的钥匙(信号量的初始值即为钥匙总量),拿到的进入C,拿不到的进入B休息室(阻塞)。S每次也只能通过一个人,其他人也需要在S外面忙等待,但通过S的时间远小于C,所以等待时间不长。从C出来后,如果B中有人,就将钥匙给B中的人,即当s.count<=0是解除阻塞进程。

     

    参考资料:操作系统:精髓与设计原理(原书第六版)

    展开全文
  • 本文分享的内容主要如下几个方面:3.1 并发的原理3.1.1 一个简单的例子3.1.2 竞争条件3.1.3 操作系统关注的问题3.1.4 进程的交互3.1.5 互斥的要求3.2 信号量原理3.2.1 互斥3.3 生产者/消费者问题3.4 读者-写者问题...

    所有学嵌入式Linux系统的看过来了,以下内容是每一位想学习Linux嵌入式系统想要了解的内容,真的很想要分享给大家!

    本文分享的内容主要如下几个方面:

    3.1 并发的原理

    3.1.1 一个简单的例子

    3.1.2 竞争条件

    3.1.3 操作系统关注的问题

    3.1.4 进程的交互

    3.1.5 互斥的要求

    3.2 信号量原理

    3.2.1 互斥

    3.3 生产者/消费者问题

    3.4 读者-写者问题

    3.3.1 读进程具有优先权

    3.3.2 写进程具有优先权

    本章首先介绍并发的概念和多个并发进程的执行。我们发现,支持并发进程的基本需求是加强互斥的能力。也就是说,当一个进程被授予互斥的能力时,那么在其活动期间,它具有排斥所有其他进程的能。

    本章通过两个经典的并发问题来说明并发的概念,并对本书中使用的各种方法进行比较。在本章开始

    将介绍一个可运行的例子——生产者/消费者问题,读者-写者问题。

    e8b3ae9330913f5ce1fb2cc240163ffe.png

    3.1 并发的原理

    在单处理器多道程序设计系统中,进程被交替执行,表现出一种并发执行的外部特征。即使不能实现真正的并行处理,并且即使在进程间来回切换需要一定的开销,交替执行在处理效率和程序构造上还是带来了重要的好处。

    在单处理器的情况下,问题源于多道程序设计系统的一个基本特性:进程的相对执行速度不可预测,

    它取决于其他进程的活动、操作系统处理中断的方式以及操作系统的调度策略。这就带来了下列困难:

     全局资源的共享充满了危险。例如,如果两个进程都使用同一个全局变量,并且都对该变量执行读

    写操作,那么不同的读写执行顺序是非常关键的。关于这个问题的例子将在下一小节中给出。

     操作系统很难对分配资源进行最优化的管理。例如,进程 A 可能请求使用一个特定的 I/O 通道,并

    获得控制权,但它在使用这个通道前被挂起了,操作系统仍然锁定这个通道,以防止其他进程使用,

    这是难以令人满意的。此外,这还会导致死锁。

     定位程序设计错误是非常困难的。这是因为结果通常是不确定的和不可再现的。

    上述所有困难在多处理器系统中都有具体的表现,因为在这样的系统中进程执行的相对速度也是不可

    预测的。一个多处理器系统还必须处理多个进程同时执行所引发的问题,从根本上来说,这些问题和单处

    理器系统中的是相同的。这些问题随着讨论的深入将逐渐明了。

    3.1.1 一个简单的例子

    考虑下面的过程:

    24aa1ee8ce03b51ec205913b70e274c9.png
    c19d4cc3ec1a49b87d3c4129de1599be.png

    为理解如何解决与执行速度无关的问题,我们首先需要考虑进程间的交互方式。

    3.1.4 进程的交互

    1 、进程中的资源争用

    当并发进程竞争使用同一个资源时,它们互相之间会发生冲突。我们可以把这种情况简单描述如下:

    两个或更多的进程在它们的执行过程中需要访问一个资源,每个进程并不知道其他进程的存在,并且每个进程也不受其他进程的执行的影响。每个进程都不影响它所使用的资源的状态,这类资源包括 I/O 设备、存储器、处理器时间和时钟。

    竞争进程间没有任何信息交换,但是一个进程的执行可能会影响到竞争进程的行为。特别是如果两个进程都期望访问同一个资源,操作系统把这个资源分配给一个进程,另一个就必须等待。因此,被拒绝访

    问的进程速度就会变慢。一种极端情况是,被阻塞的进程永远不能访问这个资源,因此一直不能成功地终止。

    竞争进程面临三个控制问题。首先是互斥的要求。假设两个或更多的进程需要访问一个不可共享的资

    源,如打印机。在执行过程中,每个进程都给该 I/O 设备发命令,接收状态信息,发送数据和接收数据。

    我们把这类资源称为临界资源,使用临界资源的那一部分代码称为程序的临界区。一次只允许有一个程序在临界区中,这一点是非常重要的。由于不清楚详细要求,我们不能仅仅依靠操作系统来理解和增强这个限制。例如在打印机的例子中,我们希望任何一个进程在打印整个文件时都拥有打印机的控制权,否则在打印结果中就会穿插着来自竞争资源的打印内容。

    实施互斥产生了两个额外的控制问题。一个是 死锁。例如,考虑两个进程 Pl 和 P2,以及两个资源 Rl

    和 R2,假设每个进程为执行部分功能都需要访问这两个资源,那么就有可能出现下列情况:操作系统把 Rl分配给 P2,把 R2 分配给 Pl,每个进程都在等待另一个资源,并且在获得其他资源并完成需要这两个资源的功能之前,谁都不会释放自己已经拥有的资源。这样,这两个进程就发生了死锁

    另一个控制问题是 饥饿。假设有三个进程(P1、P2 和 P3),每个进程都周期性地访问资源 R。考虑这种情况,Pl 拥有资源,P2 和 P3 都被延迟,等待这个资源。当 Pl 退出临界区时,P2 和 P3 都允许访问 R。假设操作系统把访问权授予 P3,并且在 P3 完成临界区之前 PI 又需要访问该临界区,如果在 P3 结束后操作系统又把访问权授予 Pl,并且接下来把访问权轮流授予 Pl 和 P3,那么即使没有死锁,P2 也可能无限期地被拒绝访问资源。

    由于操作系统负责分配资源,竞争的控制不可避免地涉及到操作系统。此外,进程自身需要能够以某

    种方式表达互斥的要求,如在使用资源前锁定资源,但任何一种解决方案都涉及到操作系统的某些支持,如提供锁机制。图 3.2 用抽象术语给出了互斥机制。假设有 n 个进程并发执行,每个进程包括(1)在某些资源 Ra 上操作的临界区,(2)不涉及访问资源 Ra 的额外代码。因为所有的进程都需要访问同一资源 Ra,因此保证在同一时刻只有一个进程在临界区是很重要的。为实现互斥,需要两个函数:entercritical 和exitcritical。每个函数的参数都是竞争使用的资源名,如果另外一个进程在临界区中,那么任何试图进入关于同一个资源的临界区的讲程都必须等待。

    d71f8e4db2dc6a46cbe0f69d756d9e67.png
    ce77742d571a5b2cbe788c77d8c682ec.png
    60a83eca905f608c7b686a08f654e0e6.png
    7bf991539fd3ae876701b64387c73848.png
    812fe4fb503a7bc6fb78cdd596ab6a30.png
    065e70c8485f65e5177cf167da0f4543.png
    e91fc025efaacd117cd6563777bf93cc.png
    097cc4f8a87d0fe16baf2c6accc7b297.png
    7fc9c83d1eaf5a0c2dc9a051a0f0aab3.png
    68c5b64124498fa024cc0a6c9432d9eb.png
    9a2935f1a7919eefc66cd64e544b57f4.png
    dbde0afbffc0fcc57c7ecc2cc3de2b3f.png
    c9568a85d85716057569c7c9e729ee02.png
    3b47bc114e0c38816fe1c76352860b15.png
    1a1e927b6dc59bda8b2cca297a6af522.png

    本章总结

    现代操作系统的中心方案是多道程序设计、多处理和分布式处理,这些方案的基础以及操作系统设计

    技术的基础是并发。当多个进程并发执行时,不论是在多处理器系统的情况下,还是在单处理器多道程序系统中,都会产生解决冲突和合作的问题。

    并发进程可以按多种方式进行交互。互相之间不知道对方的进程可能需要竞争使用资源,如处理器时

    间或对 I/O 设备的访问。进程间由于共享访问一个公共对象,如主存中的一块空间或一个文件,可能间接知道对方,这类交互中产生的重要问题是互斥和死锁。

    互斥是指,对一组并发进程,一次只有一个进程能够访问一个给定的资源或执行一个给定的功能。互

    斥技术可以用于解决诸如资源争用之类的冲突,还可以用于进程间的同步,使得它们可以合作。后一种情况的一个例子是生产者/消费者模型,一个进程往缓冲区中放数据,另一个或更多的进程从缓冲区中取数据。

    支持互斥的第二种方法涉及到使用专门的机器指令,这种方法减少了开销;但由于使用了忙等待,因

    而仍然是低效的。

    支持互斥的另一种方法是在操作系统中提供功能,其中最常见的两种技术是信号量和消息机制。信号

    量用于在进程间发信号,并可以很容易地用于实施一个互斥规定。消息对实施互斥是很有用的,它还为进程间的通信提供了一种有效的方法。

    死锁是指一组争用系统资源或互相通信的进程被阻塞的现象。阻塞是永久的,除非操作系统采取某些

    非常的行动,如杀死一个或多个进程,或者强迫一个或多个进程沿原路返回。死锁可能涉及到可重用资源或可消费资源。可重用资源是指不会因为使用而被耗尽或毁灭的资源,如 I/O 通道或存储器区域。可消费资源是指当被一个进程获得时就毁灭了的资源,这类资源的例子有消息和 I/O 缓冲区中的信息。

    处理死锁通常有三种方法:预防、检测和避免。死锁预防通过确保死锁的一个必要条件不会满足,保

    证不会发生死锁。本章没有对检测和避免进行深入讨论。

    展开全文
  • 小实验二:使用Windows互斥信号量操作函数解决上述线程并发问题,并分析、尝试和讨论线程执行体中有关信号量操作函数调用的正确位置 小实验三:根据同步机制的Peterson软件解决方案尝试自己编程实现线程同步机制和...
  • 点击上方蓝字关注我,我们一起学编程欢迎小伙伴们分享、转载、私信、赞赏小伙伴儿们看完以后可不可以帮我点亮一下在看呀~信号量与进程同步、互斥1 进程同步2 进程互斥3 信号量机制3.1 整型信号量3.2 记录型信号量4 ...

    点击上方蓝字关注我,我们一起学编程欢迎小伙伴们分享、转载、私信、赞赏

    小伙伴儿们看完以后可不可以帮我点亮一下在看呀~

    信号量与进程同步、互斥

    1 进程同步2 进程互斥3 信号量机制3.1 整型信号量3.2 记录型信号量4 用信号量实现进程互斥、同步4.1 用信号量实现进程互斥4.2 用信号量实现进程同步5 哲学家进餐问题

    1 进程同步

    我们知道,进程具有异步性的特征。异步性是指:各并发执行的进程以各自独立的、不可预知的速度向前推进。

    而同步又称直接制约关系,它是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而产生的制约关系。

    2 进程互斥

    我们把一个时间段内只允许一个进程使用的资源称为临界资源。许多物理设备(摄像头、打印机等)都属于临界资源。对临界资源的访问,必须互斥地进行。

    互斥亦称间接制约关系进程互斥是指当一个进程访问某临界资源时,另一个想要访问该临界资源的进程必须等待。当前访问临界资源的进程访问结束,释放该资源之后,另一个进程才能去访问临界资源。

    3 信号量机制

    用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便地实现进程互斥与进程同步。

    原语:是一种特殊的程序段,其执行只能一气呵成,不可被中断。原语是由关中断/开中断指令实现的。信号量:其实就是一个变量(可以是一个整型变量,也可以是更复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量。

    上面提到的操作系统提供的一对原语,是指:wait(S)原语和signal(S)原语。这一对原语常被分别称之为 P、V 操作wait(S)signal(S)两个操作分别写为 P(s)V(S)

    3.1 整型信号量

    用一个整型变量作为信号量,用来表示系统中某种资源的数量。

    下面用一个例子来说明:某计算机系统中有一台打印机。

    int S = 1;             // 初始化整型信号量S,表示当前系统中可用的打印机资源数

    void wait(int S)       // wait原语,相当于“进入区”{
        while (S <= 0);    // 如果资源数不够,就一直循环等待
        --S;               // 如果资源数够,就占用一个资源
    }

    void signal (int S)    // signal原语,相当于“退出区”{
        ++S;               // 使用资源后,在退出区释放资源
    }

    /* 进程P0 */
    ...
    wait(S);               // 进入区,申请资源
    使用打印机资源          // 临界区,使用资源
    signal(S);             // 退出区,释放资源
    ...

    /* 进程P1 */
    ...
    wait(S);               // 进入区,申请资源
    使用打印机资源          // 临界区,使用资源
    signal(S);             // 退出区,释放资源
    ...

    3.2 记录型信号量

    上面介绍的整型信号量有一个缺陷是:当资源不可用时,执行原地盲等。为了弥补这个不足,人们又提出“记录型信号量”,即用记录型数据结构表示的信号量

    /* 记录型信号量的定义 */
    typedef struct {
        int value;            // 剩余资源数
        struct process *L;    // 等待队列
    } semaphore;

    /* 某进程需要使用资源时,通过wait原语申请 */
    void wait(semaphore S){
        --S.value;            // 拟占用资源
        if (S.value 0) {    // 若资源不可用则阻塞等待资源
            block(S.L);
        }
    }

    /* 进程使用完资源后,通过signal原语释放 */
    void signal(semaphore S){
        ++S.value;             // 释放资源
        if (S.value <= 0) {    // 若有进程正等待该类资源则将其唤醒
            wakeup(S.L);
        }
    }

    wait 中,若执行 --S.value 后其值小于 0 了,说明之前就已经是小于等于 0 了,也就是说没有可用的资源了,那么就使用 block 原语使进程从运行态进入阻塞态,并将其挂到信号量 S 的等待队列当中。

    signal 中,若执行 ++S.value 后其值仍小于 0 ,说明仍然有进程在等待这种资源,那么就使用 wakeup 原语唤醒一个进程,通知其使用资源。

    下面来看一个例子:某计算机系统中有两台打印机。

    /* 初始化 */
    typedef struct {
        int value;            // 2
        struct process *L;    // nullptr
    } semaphore;

    /* 进程P0
     * 剩余资源数:1
     * 等待队列:空
     */

    ...
    wait(S);
    使用打印机资源
    signal(S);
    ...

    /* 进程P1
     * 剩余资源数:0
     * 等待队列:空
     */

    ...
    wait(S);
    使用打印机资源
    signal(S);
    ...

    /* 进程P2
     * 剩余资源数:-1
     * 等待队列:P2
     */

    ...
    wait(S);
    使用打印机资源
    signal(S);
    ...

    在原语的表达中,wait(S) 可以记为 P(S) ,用于资源的申请;signal(S) 可以记为 V(S) ,用于资源的释放。

    • S.value 的初值表示系统中某种资源的数目。

    • 对信号量 S 的一次 P 操作意味着进程请求一个单位的该类资源,因此需要执行 --S.value ,表示资源数减少 1 个单位。当 S.value < 0 时表明该类资源早已分配完毕,因此进程调用 block 原语进行自我阻塞(放弃了处理机的使用权,这点不同于整型信号量)。

    • 对信号量 S 的一次 V 操作意味着进程释放一个单位的该类资源,因此需要执行 ++S.value ,表示资源数增加 1 个单位。若 S.value ≤ 0 表明依然有进程在等待该类资源,因此调用 wakeup 原语唤醒队列中的第一个进程。

    4 用信号量实现进程互斥、同步

    4.1 用信号量实现进程互斥

    步骤:

    • (1) 分析并发进程的关键活动,划定临界区

    • (2) 设置互斥信号量 mutex ,初值为 1

    我们将临界区视作为一种特殊的资源,并且只有 1 个这样的资源。只有其他进程退出(释放资源)临界区,另一个进程才能进入临界区。

    • 在临界区之前执行 P(mutex)

    • 在临界区之后执行 v(mutex)

    上述步骤,在临界区之前执行 P(mutex) ,可以申请临界区资源,如果有这样的资源则占用,若没有则等待。当一个进程退出临界区时,先执行 V(mutex) 操作释放临界区资源,再判断是否有进程正在等待进入临界区,有的话则唤醒该进程。

    4.2 用信号量实现进程同步

    进程同步,即要求各并发执行的进程按要求有序地推进。

    步骤:

    • 分析何处需要实现“同步关系”,即保证“一前一后”执行的两个操作

    • 设置同步信号量 S ,初始值为 0

    • 在“前操作”之后执行 V(S)

    • 在“后操作”之前执行 P(S)

    为何要将信号量初始化为 0 呢?
    因为,我们默认系统中没有这样的资源。那么我们在“后操作”之前执行 P 操作申请这样的资源就会失败,所以“后操作”不能被执行。只有在“前操作”完成之后,我们执行 V 操作,这样会导致我们“释放一个”该类资源(其实是凭空产生)。此时“后操作”等待的资源已具备,因而“后操作”得以顺利执行。因而实现了两个操作的前后顺序控制。

    5 哲学家进餐问题

    问题描述:

    一张圆桌上坐着 5 名哲学家,每两个哲学家之间有一根筷子,桌子的中间是一份餐食。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响其他人。只有哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)进餐。如果要拿的筷子已在他人手上,则需等待。用餐完毕后,将筷子放回原处。

    13f48c8cc77769b5bd8694cb28acff5e.png

    • 关系分析
      系统中有 5 个哲学家进程,5 位哲学家与左右邻居对其中间筷子的访问是互斥关系

    • 整理思路
      每个哲学家需要同时持有两个互斥资源才能开始用餐。如何避免临界资源分配不当造成的死锁现象,是哲学家进餐问题的精髓。

    • 信号量设置
      定义互斥信号量数组 chopstick[5] = {1,1,1,1,1} 用于实现对 5 根筷子的互斥访问。

    哲学家 i 左边的筷子编号为 i ,右边的筷子编号为 (i+1)%5 。

    semaphore chopstick[5] = {11111};
    Pi() {                                // 哲学家i的进程
        while (1) {
            P(chopstick[i]);              // 拿左
            P(chopstick[(i + 1) % 5]);    // 拿右
            吃饭
            V(chopstick[i]);              // 放左
            V(chopstick[(i + 1) % 5]);    // 放右
            思考
        }
    }

    若 5 个哲学家并发地拿起了自己左手边地筷子,又在循环等待右手边地筷子,这就导致了死锁。

    为了解决这个问题,我们可以做出一些限制:在同一时间,只允许一位哲学家尝试拿起筷子进餐。为此,我们需要设置一个初始值为 1 的互斥信号量。

    semaphore chopstick[5] = {11111};
    semaphore mutex = 1;
    Pi() {                                // 哲学家i的进程
        while (1) {
            P(mutex);                     // 互斥地取筷子
            P(chopstick[i]);              // 拿左
            P(chopstick[(i + 1) % 5]);    // 拿右
            V(mutex);                     // 已经取好筷子
            吃饭
            V(chopstick[i]);              // 放左
            V(chopstick[(i + 1) % 5]);    // 放右
            思考
        }
    }
    展开全文
  • 文章目录进程同步与互斥、信号量机制一、进程同步、进程互斥的概念1.1 进程同步1.2 进程互斥二、进程互斥的实现方法2.1 进程互斥的软件实现方法...信号量机制实现进程互斥与同步3.3 生产者与消费者问题3.4 读写模型问题...
  • 信号量 实现进程互斥与同步

    千次阅读 2018-03-24 10:25:43
    信号量基本术语 现代计算机系统中,多个...信号量(semaphore)是1965年由荷兰人Dijkstra提出的一种卓有成效的进程间同步及互斥工具。信号量在操作系统中实现时一般作为一个整数变量,这种信号量称为整型信号量。...
  • 参考:https://www.bilibili.com/video/av31584226/?p=9 进程具有异步性的特征,异步性是指,各并发执行的进程以各自独立...读进程和写进程并发地运行,由于并发必然导致异步性,因此“写数据”和“读数据”两个操作...
  • 设置互斥信号量mutex,初值为1 在进入区P(mutex)申请资源 在退出区V(mutex)释放资源 注: 对不同的临界资源需要设置不同的互斥信号量 临界资源:一次仅允许一个进程使用的共享资源 临界区:每个进程中访问临界...
  • 设置互斥信号量mutex,初始值为1 在临界区之前执行P(mutex) 在临界区之后执行V(mutex) /*信号量机制实现互斥*/ semaphore mutex = 1; // 初始化信号量 P1(){ .... P(mutex); // 使用临界资源前需要加锁 临界区...
  • 进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu ...多道技术产生的背景:针对单核,实现并发。 多道技术:多道技术中的多道指的是多个程序,多道技术的实现是为了解...
  • 2.信号量是什么 信号量可以分为以下几种 整型信号量(integer semaphore):信号量是整数,假设有信号量S,S大于等于零时代表可供并发进程使用的资源实体数,但S小于零时则表示正在等待使用临...
  • 首先介绍了信号量的定义及在信号量上可以执行的两个操作,并分别详细说明了如何利用信号量实现进程间的同步和互斥,最后结合实例说明了这两种方法在实际问题中的具体运用。  在多道程序环境下,操作系统如何实现...
  • 当一个程序中对一个固定名称的文件做了读写的操作的时候,外界通过并发式的调用这个应用的时候,可能存在多个进程同时去操作这个文件,这个时候可能会造成调用失败的问题。所以这个时候,在操作文件之前就应该给该...
  • 先上图,进程同步、互斥的概念。 进程具有异步性的特征,异步性是指各个并发执行...这些制约管理直接来自进程互斥合作。 、 上图是进程互斥的例子。 临界区是访问临界资源的地方。进入区和退出区是负责实现互斥..
  • 负责管理协调硬件,软件等计算机资源的工作,为上层用户,应用进程提供简单易用的服务,是一种系统软件 功能和目标 资源的管理者 处理机管理 存储器管理 文件管理 设备管理 向用户提供服务 命令接口(用户...
  • 信号量的使用方式和自旋锁类似,进程只有得到信号量才能执行临界区代码 但与自旋锁不同的是,当进程获取不到信号量时并不是原地打转而是睡眠等待 中断服务函数不能进行睡眠,因此信号量不能用于中断当中,如果...
  • 信号量机制的基本原理:两个或多个进程可以利用彼此间收发的简单的信号来实现“正确的”并发执行,一个进程在收到一个指定信号前,会被迫在一个确定的或者需要的地方停下来,从而保持同步或互斥。 二、整型信号量...
  • 四种进程或线程同步互斥的控制...3、信号量:为控制一个具有有限数量用户资源而设计。 4、事 件:用来通知线程有一些事件已发生,从而启动后继任务的开始。  1.临界区(Critical Section) 保证在某一时刻只有一...
  • 对于主进程来讲, 守护进程守护的是主进程的代码, 主进程代码运行完毕, 则守护进程就终止, 之后如果还有非守护子进程在运行, 那么主进程会一直等待其运行完毕后回收该子进程的资源, 不然就会产生僵尸进程 对于主线程...
  • 信号量概念:信号量又名信号灯,与其他进程间的通信方式大不相同,主要用途是保护临界资源(进程互斥)。此外进程可以根据它判定是否能够访问某些共享资源。除了用于访问控制外,还用于进程同步。 信号量分类: 二值...
  • 1.信号量1.1 概念信号量又称为信号灯(semaphore),它是用来协调不同进程间的数据对象的,本质上信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列...
  • 进程信号量(multiprocessing.Semaphore) 1. 信号量概念(相当于在锁的基础上增加计数器) 锁的概念一样 ,只不过可以设置钥匙的数量 上述讲的Lock,属于互斥锁,也就是一把钥匙配备一把锁,同时只允许锁住某一...
  • 他出名是因为图论中著名的“最短路径”算法,因为早期关于结构化编程的论战“Goto语句是有害的”,还因为他引入了名为信号量的同步原语,正是这里我们要学习的。事实上,Dijkstra及其同事发明了信号量,作为与同步...
  • 11、用信号量机制实现进程同步、互斥、前驱关系思维导图用信号量机制实现进程同步用信号量机制实现进程互斥信号量机制实现进程的前驱关系 思维导图 用信号量机制实现进程同步 先来看一下什么是进程同步: 进程...
  • 利用信号量机制解决进程同步和互斥问题   在讨论如何用信号量机制解决这个问题之前,我们应该先了解进程同步和互斥间的一些概念。 首先是进程间的两种关系:同步和互斥。所谓同步就是把异步环境下的一组并发进程...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 590
精华内容 236
热门标签
关键字:

并发进程互斥信号量