Ada 中的信号量

Semaphore in Ada

这是一项作业,我被要求在 Ada 中实现一个信号量,如下所述。

但是我已经实现了 Semaphore.adb 并在我创建的 producerconsumer_sem.adb 中调用了这个信号量。

我得到如下输出。

  1. 我不确定我的信号量初始化是否正确S: CountingSemaphore(1,1);.

  2. 我不知道我在哪里调用 S.waitS.Signal 现在我在生产者将项目放入缓冲区之前随机调用 S.wait X := I;X := I; 之后的 S.Signal。 这是正确的方法吗?

Producer-Consumer Problem The program producerconsumer.adb implements a non-reliable implemen- tation of the producer-consumer problem, where data is likely be lost. In the following, you will use three different communication mechanisms to achieve a reliable implementation of the producer-consumer problem.

Semaphore

The Ada language does not directly provide library functions for a semaphore. However, semaphores can be implemented by means of a protected object. Create a package specification Semaphore in the file Semaphores.ads and the corresponding package body in the file Semaphores.adb that implements a counting semaphore. Skeletons for the package are available on the course page.

Use the semaphore package for a reliable implementation of the producer- consumer problem. Modify the file producerconsumer.adb and save the final code as producerconsumer_sem.adb. In order to use the semaphore package it shall be installed in the same directory as producerconsumer_sem.adb. It can then be accessed by

with Semaphores; use Semaphores;

输出:

OutPut: 1 1 1 2 2 3 4 4 5 6 6 7 7 8 9 9 9 10 11 11 11 12 12 13 13 13 14 15 15 16 16 17 18 18 18 19 20 20 21 21 22 22 23 24 24 24 24 25 25 26 27 27 28 29 29 30 30 31 31 32 32 33 33 33 34 35 35 35 36 36 37 37 37 38 38 38 39 40 40 40

package Semaphores is
   protected type CountingSemaphore(Max: Natural; Initial: Natural)  is
      entry Wait;
      entry Signal;
   private
      Count : Natural := Initial;
      MaxCount : Natural := Max;
   end CountingSemaphore;
end Semaphores;

我实现的信号量semaphores.adb

package body Semaphores is
   protected body CountingSemaphore is
   entry Wait when Count > 0 is
    begin
    Count := Count - 1;

    end Wait;
      entry Signal when Count < MaxCount is
    begin
    Count := Count + 1;

    end Signal;
   end CountingSemaphore;
end Semaphores;

producerconsumer_sem.adb

with Ada.Text_IO;
use Ada.Text_IO;

with Ada.Real_Time;
use Ada.Real_Time;

with Ada.Numerics.Discrete_Random;

with Semaphores;
use Semaphores;

procedure ProducerConsumer_sem is

   X : Integer; -- Shared Variable
   N : constant Integer := 40; -- Number of produced and comsumed variables

   S: CountingSemaphore(1,1);
   --S1: CountingSemaphore(1,1);

   pragma Volatile(X); -- For a volatile object all reads and updates of
                       -- the object as a whole are performed directly
                       -- to memory (Ada Reference Manual, C.6)

   --Random Delays
   subtype Delay_Interval is Integer range 50..250;
   package Random_Delay is new Ada.Numerics.Discrete_Random
   (Delay_Interval);
   use Random_Delay;
   G : Generator;

   task Producer;

   task Consumer;

   task body Producer is
      Next : Time;
   begin
      Next := Clock;
      for I in 1..N loop
         -- Write to X
         S.Wait;
         X := I;
         S.Signal;
         --Next 'Release' in 50..250ms
         Next := Next + Milliseconds(Random(G));
         Put_Line(Integer'Image(X));
         delay until Next;
      end loop;
   end;

   task body Consumer is
      Next : Time;
   begin
      Next := Clock;
      for I in 1..N loop
         -- Read from X
         S.Wait;
         Put_Line(Integer'Image(X));
         S.Signal;
         Next := Next + Milliseconds(Random(G));
         delay until Next;
      end loop;
   end;

begin -- main task


   null;
end ProducerConsumer_sem;

在 macOS 上,使用 FSF GCC 7.1.0 和 GNAT GPL 2017,我将你的 Put_Lines 更改为 Puts 并得到了你在问题中陈述的大部分答案。

问题说创建Semaphore.ads.adb。这将适用于 Windows,并且可能适用于 macOS,但不适用于 Linux,因为 GNAT 的文件命名约定(请参阅 this 的结尾;这是一个好主意养成使用小写文件名的习惯)。

如果您想确保一次只有一个任务可以访问 X,我认为您的 WaitSignal 调用没有太大问题,不过当我在 Producer 的开头放置一个 delay 0.1 时,第一个值输出是 151619216(因为 X 未初始化)。然而!如果重点是一次向 X 传达一个更新(正如名称 producer/consumer 所暗示的那样),您应该

  • 初始化信号量为 0(最大为 1)。这使它成为二进制信号量。
  • 仅在 ConsumerWait(即删除 Signal
  • 仅在 ProducerSignal 中(即删除 Wait)。另外,删除 Put 以避免混淆!