❌ About FreshRSS

Normal view

There are new articles available, click to refresh the page.
Before yesterdayNews from the Ada programming language world

Bridge returned error 0! (19713)

22 December 2023 at 23:07

Details

Type: HttpException
Code: 0
Message: cURL error Failed to connect to tomekw.com port 443 after 189 ms: Couldn't connect to server: 7 (https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://tomekw.com/feed.xml
File: lib/http.php
Line: 127

Trace

#0 index.php(11): RssBridge->main()
#1 lib/RssBridge.php(113): DisplayAction->execute()
#2 actions/DisplayAction.php(71): DisplayAction->createResponse()
#3 actions/DisplayAction.php(106): FilterBridge->collectData()
#4 bridges/FilterBridge.php(168): FeedExpander->collectExpandableDatas()
#5 lib/FeedExpander.php(88): getContents()
#6 lib/contents.php(67): CurlHttpClient->request()
#7 lib/http.php(127)

Context

Query: action=display&bridge=Filter&url=https://tomekw.com/feed.xml&filter=Ada&filter_type=permit&format=Atom
Version: 2023-09-24
OS: Linux
PHP: 8.2.7

Go back

Frenzie, ORelio

  • 22 December 2023 at 23:07

AEiC 2024 - Ada-Europe conference - grants for Open Access publication

21 December 2023 at 17:32

Season’s greetings from the organizers of the 28th Ada-Europe International Conference on Reliable Software Technologies (AEiC 2024), to be held 11-14 June 2024, in Barcelona, Spain!

Accepted Journal Track papers will be published in the conference’s Special Issue of the Journal of Systems Architecture (JSA). Note that the Ada-Europe organization will waive the Open Access fees for the first four accepted papers, which do not already enjoy OA from other agreements with the Publisher.

www.ada-europe.org/conference2024/cfp.html#cfpjournal

#AEiC2024 #AdaEurope #AdaProgramming

1 post - 1 participant

Read full topic

AEiC 2024 - Ada-Europe conference - grants for Open Access publication

Season's greetings from the organizers of the 28th Ada-Europe International Conference on Reliable Software Technologies (AEiC 2024), to be held 11-14 June 2024, in Barcelona, Spain!

Accepted Journal Track papers will be published in the conference's Special Issue of the Journal of Systems Architecture (JSA). Note that the Ada-Europe organization will waive the Open Access fees for the first four accepted papers, which do not already enjoy OA from other agreements with the Publisher.

www.ada-europe.org/conference2024/cfp.html#cfpjournal

#AEiC2024 #AdaEurope #AdaProgramming

submitted by /u/Dirk042
[link] [comments]

2023 Day 12: Hot Springs

By: cantanima
13 December 2023 at 04:55

:scream:

just kidding. but this one took me a long time. We seem to have entered the fiendishly difficult phase. Fortunately, difficult problems are usually followed by not-so-difficult ones. Usually.

  • I first completed part 1 using a recursive algorithm that pruned failing branches. No problem, though it was a bit slow, so I knew what was coming next.
  • Yup, Part 2 inflates the input to an insane size. The first record completed quickly, to my surprise but I quit the program after it dawdled on the second record for several minutes.
  • I stared at it a while.
  • Finally, I visited the Reddit solutions page. People were mentioning spoiler. What the heck is spoiler, thinks I, feeling a little humiliated at not knowing. Scrolling down a little, I see that someone else has the wherewithal to ask. It means spoiler. Oh yeah, says I, albeit a little more colorfully. (i.e., :face_with_symbols_over_mouth:) I remember something about that from my Algorithms class. But… how?
  • Reading a bit more, I see what people say they are doing. Unfortunately, they are writing in languages like C++, D, Python, Rust. Excerpts range from illegible to incomprehensible out of their context. Probably doesn’t help that’s it’s 2am. Oooookayyyyy… time for a nap.

Thinking about it this evening, I realized that I could do the following.

  1. For each line, iterate over the contiguous groups from left to right. So, start with the leftmost.
  2. Assume the group records n damaged springs,
    • Determine spoiler.
    • For each i in 0 … spoiler A picture is probably worth 1000 words here: if n is 3, and spoiler, look at spoiler It is easy to tell whether this matches .#?#?.***
    • If it matches, take the next contiguous group and recurse (step 2) with an appropriate starting index for the next string. (Have I mentioned how I :heart: Ada’s custom indexing?.)
    • This is a key point. If you don’t want to wait forever, spoiler

A couple of additional complications I encountered:

  • The result in part 2 is larger than Natural'Last on my input, so you’ll likely need something larger.
  • If you use a hashed map for the spoiler, be prepared for some moding. I do wonder if I’d have done better with an ordered map.

There was more, but I can’t remember it now.

***I don’t recall reading this detail anywhere in the Reddit discussion of solutions, but then again, I don’t think so well at 2am. Either way, I’m pleased as punch that it seemed different.

3 posts - 2 participants

Read full topic

Using GNATTest with Alire and GNATStudio

Hi All.
For context, I am working on a small code challenge that saw online. Essentially, is implementing an Ulam Spiral, in CLI, using different languages. I did this for fun, and to learn new things on the way.

I am currently working on the implementation of the Ada language. Coming from Java/Python/Javascript backgrounds, was challenging and fun figuring out how Ada does things. I am also using Alire for some small dependency management I need.

In any case, I want to implement some unit testing, just for completion, and quick verification for other parts that may be wrong. I read some articles online, and found two things:

  1. This git repository: https://github.com/alire-project/ada_spark_workflow shows a basic library on Ada, and shows that Unit Tests can be implemented as a separate crate
  2. The documentation for AUnit (https://docs.adacore.com/live/wave/aunit/html/aunit_cb/aunit_cb.html) shows how to implement tests, suites, fixtures, etc, which seems easy enough.

However, I also came into GNATTest and how is integrated into GNATStudio (which I am using for this development). Seems that make it easier to just use it to generate the test files, while I have to provide the actual test code, asserts, etc.

I added the libadalang_tools crate as a dependency, and it compiles fine. I can even see the build binaries in a folder (location: ${project_root_folder}/alire/cache/dependencies/libadalang_tools_23.0.0_75f92679/bin). However, GNATStudio complains that the binary can not be found, which makes sense, as it is not in the PATH environment variable

Here are my questions then:

  1. Can Alire set those binaries to the path? that way, when I run `alr edit`, they will be already on the path, and all will run without any issues.
  2. If #1 is not possible, then how can I configure the path to the binaries for GNATest (and other tools if needed) in a way that is portable to others (or even a future me) who want to clone the repository and build/run the code?

As a workaround, I changed the command that is executed on the GNATtest generation window and hardcoded the path. It works, but did not feel that was the correct way.

Any help on this is very welcome. Let me know if you need other details.

Regards!

submitted by /u/egamboau
[link] [comments]

Bridge returned error 404! (19699)

8 December 2023 at 07:07

404 Page Not Found

RSS-Bridge tried to fetch a page on a website. But it doesn't exists.

Details

Type: HttpException
Code: 404
Message: https://www.youtube.com/feeds/videos.xml?channel_id=UCOC7qHXMYZe-w1737_Vv7Yg resulted in 404 Not Found
File: lib/contents.php
Line: 106

Trace

#0 index.php(11): RssBridge->main()
#1 lib/RssBridge.php(113): DisplayAction->execute()
#2 actions/DisplayAction.php(71): DisplayAction->createResponse()
#3 actions/DisplayAction.php(106): YoutubeBridge->collectData()
#4 bridges/YoutubeBridge.php(198): YoutubeBridge->collectDataInternal()
#5 bridges/YoutubeBridge.php(111): YoutubeBridge->ytGetSimpleHTMLDOM()
#6 bridges/YoutubeBridge.php(465): getSimpleHTMLDOM()
#7 lib/contents.php(157): getContents()
#8 lib/contents.php(106)

Context

Query: action=display&bridge=Youtube&context=By channel id&c=UCOC7qHXMYZe-w1737_Vv7Yg&duration_min=&duration_max=&format=Atom
Version: 2023-09-24
OS: Linux
PHP: 8.2.7

Go back

No maintainer

  • 8 December 2023 at 07:07

Generating Ada bindings for C headers (Gem #59) doesn't work any more

When I used this method a few years ago, with Ada from the Ubuntu repository, it worked fine. Now, with my installation from Adacore, not so anymore.

The method consists of 2 commands (time.h as example)

  1. g++ -c -fdump-ada-spec -C /usr/include/time.h
  2. gcc -c -gnat05 *.ads

While the first command executes without any problem, the second one returns:

gcc: fatal error: cannot execute ‘gnat1’: execvp: No such file or directory

It doesn't depend on the -gnat05 option. There is indeed no gnat1 in the bin directory of the Ada installation. Mine is version 2021. I am reluctant to install the GNU version in parallel, I might mix up things.

Any other idea?

AEiC 2024 - Ada-Europe conference - 2nd Call for Contributions

22 November 2023 at 17:16

The 28th Ada-Europe International Conference on Reliable Software Technologies (AEiC 2024) will take place in Barcelona, Spain from 11 to 14 June, and comprises different tracks and co-located events.

Submission deadlines: 15 January for journal track papers; 26 February for industrial track and work-in-progress track papers, tutorial and workshop proposals. Submit early: tutorial/workshop proposals will be evaluated ASAP, with decisions from 1 January 2024!

More information on the conference site, including an extensive list of topics, and details on the call for contributions for the various tracks.

www.ada-europe.org/conference2024

#AEiC2024 #AdaEurope #AdaProgramming

1 post - 1 participant

Read full topic

AEiC 2024 - Ada-Europe conference - 2nd Call for Contributions

The 28th Ada-Europe International Conference on Reliable Software Technologies (AEiC 2024) will take place in Barcelona, Spain from 11 to 14 June, and comprises different tracks and co-located events.

Submission deadlines: 15 January for journal track papers; 26 February for industrial track and work-in-progress track papers, tutorial and workshop proposals. Submit early: tutorial/workshop proposals will be evaluated ASAP, with decisions from 1 January 2024!

More information on the conference site, including an extensive list of topics, and details on the call for contributions for the various tracks.

www.ada-europe.org/conference2024

#AEiC2024 #AdaEurope #AdaProgramming

submitted by /u/Dirk042
[link] [comments]

Gnatprove detailed counterexample trace outside GNAT Studio?

18 November 2023 at 02:46

When gnatprove is used with “–counterexamples=on” inside GNAT Studio it is able to present a detailed trace[1]:

counterexample

This nice trace only seems to work inside GNAT Studio, not inside the VSCode AdaCore.ada plugin. Is there a way to output this trace to a text console (e.g. by passing an option to the gnatprove command-line command) so that this trace feature can be used outside GNAT Studio?

[1] 7.2. How to View GNATprove Output — SPARK User's Guide 25.0w

2 posts - 2 participants

Read full topic

Lightweight Parallelism library based on Ada 2022 features

By: sttaft
4 November 2023 at 13:46

A full implementation of the parallel features of Ada 2022 is yet to be released. In the meantime, here is a light-weight-threading library that provides essentially all of the parallel features of Ada 2022, using various generics, etc. Scheduling is provided using a plug-in architecture. If no scheduler is plugged in, the light-weight threads are simply executed sequentially. If a light-weight-thread scheduler is plugged in, then the light-weight threads spawned by instances of the various generic packages are managed by that scheduler.

There are currently two LWT scheduler plug-ins:

  • a wrapper for the GNU implementation of OpenMP (lwt-openmp.ads)
  • a work-stealing based plug-in, written entirely in Ada (lwt-work_stealing.ads)

Below is a link to the “readme.md” documentation for the GitHub lwt library. It is currently part of the ParaSail GitHub repository, but the files in “lwt” are actually independent of ParaSail. ParaSail has its own work-stealing-based scheduler built-in, but at some point we plan to shift over to using the “lwt” library. But at the moment, there is no dependence either way between the ParaSail interpreter/compiler and the lwt library.

Feel free to open GitHub Issues if you find problems with the implementation, or have suggestions for improvements.

Enjoy!

-Tucker Taft

The ParaSail GitHub repository was created by my colleague Olivier Henley, and he has also helped to improve the documentation and testing scripts. Much appreciated!

2 posts - 2 participants

Read full topic

An interesting thing happened to me yesterday.

TLDR: Ada is a great language!

I thought I would share. So, a PLC (Mitsubishi FX5UC) was brought to my work table yesterday. I was supposed to try to establish communication with it. I wrote a Missubishi communication driver back in 2021 for our SCADA system. In Ada, naturally, as most of our system is in Ada :)

The communication can be either via UDP or TCP, somewhat similar but more complicated than Modbus (more addressing modes, more types of variables). In 2021, it took me some 10 man-days to write using the available Mitsubishi documentation (500 pages) which is so good it even contains packet samples (which I used for dry tests as at the time, I had no available Mitsubishi PLC). The result was some 80 kB source file (adb) with a small 3kB specification (ads). (I don't count changes needed to add a new communication protocol to the SCADA).

Now, after yesterday's testing I had to:

  • replace calling one socket-reading function with another (mistakenly I used 'read until the output buffer is full' instead of 'read what data is available')
  • add one line (multiplication by 2) handling the fact that a word register has 2 bytes
  • add 'else' branch to initialize a variable
  • modify 2 comments (a reference to a wrong page of Mitsubishi documentation)
  • to make writing to a bit variable work, change a constant (2#0001_0000" instead of 1 as a high nibble is used for the 1st bit, low for the second bit).

That's all. After 2.5 hours I was able to read/write all the required variable types. After another 2.5 hours, I checked all the types in our driver documentation (and discovered one more typo - one of the variable types was a word instead of a bit).

I'm no great programmer and I usually generate quite a lot of mistakes, so this time I was pleasantly surprised that with a few corrections, my code actually started to work quite quickly. I think the choice of a programming language has a lot to do with it ... ;-)

submitted by /u/PeterHumaj
[link] [comments]

Ada interfacing C++: instance destroyed

I want to use a C++ library that implements the Factory Method design pattern.

Below you can see a minimal reproducibable example, including C++ sources and the Ada adapter.

  • Item.h:

    // Product interface
    
    #ifndef _ITEM_H_
    #define _ITEM_H_
    
    class Item {
    public:
    
      virtual ~Item() = default;
      virtual void do_something() = 0;
    };
    
    #endif
    
  • ConcreteItem.h:

    
    #ifndef _CONCRETEITEM_H_
    #define _CONCRETEITEM_H_
    
    #include "Item.h"
    
    class ConcreteItem : public Item {
    public:
      ConcreteItem();
      ~ConcreteItem();
      void do_something();
    };
    
    #endif
    
  • ConcreteItem.cpp:

    
    #include <stdlib.h>
    #include <iostream>
    #include "ConcreteItem.h"
    
    void ConcreteItem::do_something() {
      std::cout << "Doing stuff \n";
    };
    
    ConcreteItem::ConcreteItem() {
      std::cout << "Concrete Item created \n";
    };
    
    ConcreteItem::~ConcreteItem(){
      std::cout << "Concrete Item destroyed \n";
    };
    
  • Factory.h:

    
    #ifndef _FACTORY_H_
    #define _FACTORY_H_
    
    #include "Item.h"
    
    class Factory {
    public:
      static Item* get_configured_item ();
      Factory(Factory& other) = delete;
    
    private:
    
      static Factory* factory;
      static Item* config_item;
    
      Factory();
      ~Factory();
    };
    
    #endif
    
  • Factory.cpp:

    
    #include "Factory.h"
    #include "ConcreteItem.h"
    
    Factory* Factory::factory = nullptr;
    Item* Factory::config_item = nullptr;
    
    Item *Factory::get_configured_item() {
    
      if (Factory::factory == nullptr) {
        Factory::factory = new Factory();
    
        if (Factory::config_item == nullptr) {
          Factory::config_item = new ConcreteItem();
        };
      };
    
      return Factory::config_item;
    };
    
    Factory::Factory(){};
    Factory::~Factory() {
      delete Factory::config_item;
    };
    

And here I have the Ada files that imports C++ symbols, generated with a call to g++ -c -fdump-ada-spec -C ./Factory.h and doing some modifications to suite my taste:

  • Factory_h.ads:
    limited with Item_h;
    
    package Factory_h is
    
      type Factory is limited record
        null;
      end record
        with Import => True,
        Convention => CPP;
    
      function get_configured_item return access Item_h.Item'Class  -- ./Factory.h:9
        with Import => True, 
        Convention => CPP, 
        External_Name => "_ZN7Factory19get_configured_itemEv";
    
    end Factory_h;
    
  • Item_h.ads:
    
    with Interfaces.C;
    
    package Item_h is
      type Item is limited interface
        with Import => True,
        Convention => CPP;
    
      --  procedure Delete_Item (this : access Item) is abstract;-- ./Item.h:8
      --  
      --  procedure Delete_And_Free_Item (this : access Item) is abstract; -- ./Item.h:8;
    
      procedure do_something (this : access Item) is abstract;  -- ./Item.h:9
    end Item_h;
    

And finaly an Ada main to test this silly example:

with Factory_h;
with Item_h;

procedure main is
  
  configured_item : constant access Item_h.Item'Class :=
    Factory_h.get_configured_item;
  
begin
  
  configured_item.do_something;

end main;

Do you know why if I comment out the Item primitives Delete_Item and Delete_And_Free_Item the call to do_something is never done and the item is destroyed?

If I uncomment them everything works.

Thanks in advance!

Implementing Release for GNATCOLL.Refcount

19 October 2023 at 15:28

GNATCOLL.Refcount provides a procedure to run some code when the reference-counted element is released.

How do I implement this procedure?

I’m clearly missing something because Release is not visible as GNATCOLL.Refcount.Release and this doesn’t work

type Context_Contents is new GNATCOLL.Refcount.Refcounted with record
    Address : System.Address;
end record;

procedure Release is new GNATCOLL.Refcount.Release
   (Self => Context_Contents);

and gives me

usb.ads:29:47: error: "Release" not declared in "Refcount"

4 posts - 3 participants

Read full topic

Parallel Comparison of C++ and Ada Producer-Consumer Implementations

 

Producer Consumer Comparison 

The C++ source code for this example is taken from the blog post here by Andrew Wei. A detailed description of the C++ software is given in the blog post.

This solution is shown in parallel with a corresponding Ada solution.

Both C++ and Ada separate interface specifications from implementation. C++ uses the header file, in this case the file named Buffer.hpp, to provide the interface specification for the buffer used in this example. C++ is not very strict about what goes into a header file and what goes into a .cpp file. The Ada version creates an Ada package. The Ada package specification defines the task types named producer_Int and consumer_Int. The buffer shared by all instances of producer_int and consumer_int is defined within the Ada package body file.

Interface Specification Files

Ada C++
package pc_tasks is
   task type produce_Int (Id : Natural);
   task type consume_Int (Id : Natural);
end pc_tasks;
//
//  Buffer.hpp
//  ProducerConsumer
//
//  Created by Andrew Wei on 5/31/21.
//

#ifndef Buffer_hpp
#define Buffer_hpp

#include <mutex>
#include <condition_variable>
#include <stdio.h>
 
#define BUFFER_CAPACITY 10

class Buffer {
    // Buffer fields
    int buffer [BUFFER_CAPACITY];
    int buffer_size;
    int left; // index where variables are put inside of buffer (produced)
    int right; // index where variables are removed from buffer (consumed)
    
    // Fields for concurrency
    std::mutex mtx;
    std::condition_variable not_empty;
    std::condition_variable not_full;
    
public:
    // Place integer inside of buffer
    void produce(int thread_id, int num);
    
    // Remove integer from buffer
    int consume(int thread_id);
    
    Buffer();
};

#endif /* Buffer_hpp */

This comparison shows the interface for Ada task types while the C++ interface (.hpp) file shows the interface for the Buffer class. The C++ interface definition defines the interfaces, both public and private, to the Buffer class.

Shared Buffer Implementations

The Ada package body contains both the definition and implementation of the shared buffer object and the implementation of the task types.

Ada C++
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Numerics.Discrete_Random;

package body pc_tasks is
   type Index_T is mod 10; -- Modular type for 10 values
   type Circular_Array is array (Index_T) of Integer;

   protected buffer is
      entry produce (Item : in Integer);
      entry consume (Item : out Integer);
   private
      Buf      : Circular_Array;
      P_Index  : Index_T := Index_T'First;
      C_Index  : Index_T := Index_T'First;
      Buf_Size : Natural := 0;
   end buffer;

   protected body buffer is
      entry produce (Item : in Integer) when Buf_Size < Index_T'Modulus is
      begin
         Buf (P_Index) := Item;
         P_Index       := P_Index + 1;
         Buf_Size      := Buf_Size + 1;
      end produce;

      entry consume (Item : out Integer) when Buf_Size > 0 is
      begin
         Item     := Buf (C_Index);
         C_Index  := C_Index + 1;
         Buf_Size := Buf_Size - 1;
      end consume;
   end buffer;

   task body produce_Int is
      subtype decimal is Integer range 1 .. 10;
      package rand_int is new Ada.Numerics.Discrete_Random (decimal);
      use rand_int;
      value : decimal;
      seed  : Generator;
   begin
      Reset (seed);
      for I in 1 .. 4 loop
         value := Random (seed);
         buffer.produce (value);
         Put_Line ("Task" & Id'Image & " produced" & value'Image);
         delay 0.1;
      end loop;
   end produce_Int;

   task body consume_Int is
      Num : Integer;
   begin
      for I in 1 .. 6 loop
         buffer.consume (Num);
         Put_Line ("Task" & Id'Image & " consumed" & Num'Image);
         delay 0.1;
      end loop;
   end consume_Int;

end pc_tasks;
//
//  Buffer.cpp
//  ProducerConsumer
//
//  Created by Andrew Wei on 5/31/21.
//

#include <iostream>
#include "Buffer.hpp"

Buffer::Buffer() {
    buffer_size = 0;
    left = 0;
    right = 0;
}

void Buffer::produce(int thread_id, int num) {
    // Acquire a unique lock on the mutex
    std::unique_lock<std::mutex> unique_lock(mtx);
    
    std::cout << "thread " << thread_id << " produced " << num << "\n";
    
    // Wait if the buffer is full
    not_full.wait(unique_lock, [this]() {
        return buffer_size != BUFFER_CAPACITY;
    });
    
    // Add input to buffer
    buffer[right] = num;
    
    // Update appropriate fields
    right = (right + 1) % BUFFER_CAPACITY;
    buffer_size++;
    
    // Unlock unique lock
    unique_lock.unlock();
    
    // Notify a single thread that buffer isn't empty
    not_empty.notify_one();
}

int Buffer::consume(int thread_id) {
    // Acquire a unique lock on the mutex
    std::unique_lock<std::mutex> unique_lock(mtx);
    
    // Wait if buffer is empty
    not_empty.wait(unique_lock, [this]() {
        return buffer_size != 0;
    });
    
    // Getvalue from position to remove in buffer
    int result = buffer[left];
    
    std::cout << "thread " << thread_id << " consumed " << result << "\n";
    
    // Update appropriate fields
    left = (left + 1) % BUFFER_CAPACITY;
    buffer_size--;
    
    // Unlock unique lock
    unique_lock.unlock();
    
    // Notify a single thread that the buffer isn't full
    not_full.notify_one();
    
    // Return result
    return result;
}

The Ada part of the package implementing the shared buffer is isolated below, along with a repeat of the C++ Buffer class implementation.

Ada C++
   type Index_T is mod 10; -- Modular type for 10 values
   type Circular_Array is array (Index_T) of Integer;

   protected buffer is
      entry produce (Item : in Integer);
      entry consume (Item : out Integer);
   private
      Buf      : Circular_Array;
      P_Index  : Index_T := Index_T'First;
      C_Index  : Index_T := Index_T'First;
      Buf_Size : Natural := 0;
   end buffer;

   protected body buffer is
      entry produce (Item : in Integer) when Buf_Size < Index_T'Modulus is
      begin
         Buf (P_Index) := Item;
         P_Index       := P_Index + 1;
         Buf_Size      := Buf_Size + 1;
      end produce;

      entry consume (Item : out Integer) when Buf_Size > 0 is
      begin
         Item     := Buf (C_Index);
         C_Index  := C_Index + 1;
         Buf_Size := Buf_Size - 1;
      end consume;
   end buffer;
//
//  Buffer.cpp
//  ProducerConsumer
//
//  Created by Andrew Wei on 5/31/21.
//

#include <iostream>
#include "Buffer.hpp"

Buffer::Buffer() {
    buffer_size = 0;
    left = 0;
    right = 0;
}

void Buffer::produce(int thread_id, int num) {
    // Acquire a unique lock on the mutex
    std::unique_lock<std::mutex> unique_lock(mtx);
    
    std::cout << "thread " << thread_id << " produced " << num << "\n";
    
    // Wait if the buffer is full
    not_full.wait(unique_lock, [this]() {
        return buffer_size != BUFFER_CAPACITY;
    });
    
    // Add input to buffer
    buffer[right] = num;
    
    // Update appropriate fields
    right = (right + 1) % BUFFER_CAPACITY;
    buffer_size++;
    
    // Unlock unique lock
    unique_lock.unlock();
    
    // Notify a single thread that buffer isn't empty
    not_empty.notify_one();
}

int Buffer::consume(int thread_id) {
    // Acquire a unique lock on the mutex
    std::unique_lock<std::mutex> unique_lock(mtx);
    
    // Wait if buffer is empty
    not_empty.wait(unique_lock, [this]() {
        return buffer_size != 0;
    });
    
    // Getvalue from position to remove in buffer
    int result = buffer[left];
    
    std::cout << "thread " << thread_id << " consumed " << result << "\n";
    
    // Update appropriate fields
    left = (left + 1) % BUFFER_CAPACITY;
    buffer_size--;
    
    // Unlock unique lock
    unique_lock.unlock();
    
    // Notify a single thread that the buffer isn't full
    not_full.notify_one();
    
    // Return result
    return result;
}

 The Ada buffer definition begins by defining the array type to be used in the shared buffer. Ada allows arrays to be indexed by any discrete type. In this example an Ada modular type is declared and named Index_T. Type Index_T is declared to be "mod 10", which specifies that all its values are in the range of 0 through 9 and all the arithmetic operators return a value within this range. The only arithmetic operator used in this example is "+". Addition on a modular type is modular. Thus, in this example, 9 + 1 yields 0, which is exactly as needed for a circular buffer.

Type Circular_Array is an array indexed by Index_T. Every element of Circular_Array is an Integer.

Ada protected objects are protected against race conditions. They are specifically used for data shared by Ada tasks. Ada tasks are commonly implemented as operating system threads, but may also be used on a bare-bones system using only a compiler-generated Ada runtime.

The protected object is named buffer. It is separated into a specification and an implementation, but both parts in this example are contained in the package body. The protected specification declares the name of the protected object. There are three kinds of methods that may be used inside a protected object: procedures, entries and functions. Procedures have exclusive unconditional read-write access to the data in the protected object. Entries have conditional read-write access to the data in a shared object. Functions have shared read-only access to the data in the protected object. This example only uses two entries. The private portion of the protected object contains the definition of the data members in the protected object. Buf is an instance of Circular_Array. P_Index is an instance of the Index_T type and is used by the producer to add new data to the protected object. C_Index is an instance of Index_T type and is used by the consumer to index data read from the protected object. Buf_Size is an instance of the Natural subtype of Integer. Natural is a pre-defined subtype of Integer with a minimum value of 0. Buf_Size is initialized with the value 0.

The protected body implements the two entries. Each entry has an associated condition which must evaluate to True for the entry to execute. All tasks calling an entry while its controlling condition evaluates to False are implicitly placed in an entry queue for the called entry using a queuing policy of First-In-First-Out (FIFO). The next entry call in the queue is serviced as soon as the condition evaluates to TRUE. Tasks suspended in the entry queue are given access to the protected entry before any new tasks, thus maintaining the temporal condition of the calls.

The produce entry can only write to the protected object when Buf_Size is less than Index_T'Modulus, which in this case evaluates to 10. The consumer entry can only read from the protected object when Buf_Size is greater than 0.

Each entry implicitly handles all locking and unlocking of the protected object. The protected object is locked just before the "begin" reserved word in each entry and is unlocked just before the "end" reserved word in each entry. The modular nature of the index manipulations as well as the implicit lock manipulations explain the relatively simple Ada code compared with the more verbose corresponding C++ code.

Thread Implementations

The Ada task implementations are also contained in the package body while the C++ thread implementations are contained in the main.cpp file. Those corresponding source code sections are compared below.

Ada C++
   task body produce_Int is
      subtype decimal is Integer range 1 .. 10;
      package rand_int is new Ada.Numerics.Discrete_Random (decimal);
      use rand_int;
      value : decimal;
      seed  : Generator;
   begin
      Reset (seed);
      for I in 1 .. 4 loop
         value := Random (seed);
         buffer.produce (value);
         Put_Line ("Task" & Id'Image & " produced" & value'Image);
         delay 0.1;
      end loop;
   end produce_Int;

   task body consume_Int is
      Num : Integer;
   begin
      for I in 1 .. 6 loop
         buffer.consume (Num);
         Put_Line ("Task" & Id'Image & " consumed" & Num'Image);
         delay 0.1;
      end loop;
   end consume_Int;
// Takes in reference to a buffer and adds a random integer
void produceInt(Buffer &buffer) {
    for (int i = 0; i < 4; i++) {
        // Generate random number between 1 and 10
        int new_int = rand() % 10 + 1;
        buffer.produce(i, new_int);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

// Takes in reference to a buffer and returns the latest int added
// in the buffer
void consumeInt(Buffer &buffer) {
    for (int i = 0; i < 6; i++) {
        buffer.consume(i);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

The Ada tasks have visibility to the buffer protected object because the task bodies and the protected object are both defined within the same package body scope.

The produce_Int task defines an Integer subtype named decimal with valid values in the range of 1 through 10. That type is passed to the generic package Ada.Numerics.Discrete_Random so that random numbers in the range of 1 through 10 will be generated for this program. The random number seed is reset based upon the system clock using the Reset(seed) command. The for loop iterates through the values 1 through 4. Each iteration generates a new random value, writes the value to buffer.produce, outputs the value to standard output and then delays 0.1 seconds (100 milliseconds).

The consumer_int task defines a local integer variable named Num. The for loop iterates through the numbers 1 through 6. Each iteration calls buffer.consume, assigning the entry out parameter to Num, outputs the consumed value and delays 0.1 seconds.

Program Entry Points

While the program entry point for a C++ program is named "main", the program entry point for an Ada program may have any name chosen by the programmer. Note that the Ada entry point is a procedure, meaning it does not return any value and that procedure has no parameters.

Ada C++
with pc_tasks;    use pc_tasks;
with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
begin
   Put_Line("Executing code in main...");
   declare
      Produce_Task0 : produce_Int (0);
      Consume_Task0 : consume_Int (1);
      Produce_Task1 : produce_Int (2);
      Consume_Task1 : consume_Int (3);
      Produce_Task2 : produce_Int (4);
   begin
      null;
   end;
   Put_Line ("Done!");
end Main;
int main(int argc, const char * argv[]) {
    std::cout << "Executing code in main...\n";
    
    // Initialize random seed
    srand (time(NULL));
    
    // Create Buffer
    Buffer buffer;
    
    // Create a thread to produce
    std::thread produceThread0(produceInt, std::ref(buffer));
    
    std::thread consumeThread0(consumeInt, std::ref(buffer));
    
    std::thread produceThread1(produceInt, std::ref(buffer));
    
    std::thread consumeThread1(consumeInt, std::ref(buffer));
    
    std::thread produceThread2(produceInt, std::ref(buffer));
    
    produceThread0.join();
    produceThread1.join();
    produceThread2.join();
    consumeThread0.join();
    consumeThread1.join();
    
    std::cout << "Done!\n";
    return 0;
}

Ada does not provide a "join()" method. Instead, the code block in which a task or set of task is declared cannot complete until all the tasks within that code block complete. The idiom shown above declared the 5 task type instances within an inner code block, which does not complete until all five of the tasks have terminated. Upon completion of that inner block the message "Done!" is output to standard output.

Complete code listings for both languages

Ada C++
package pc_tasks is
   task type produce_Int (Id : Natural);
   task type consume_Int (Id : Natural);
end pc_tasks;
//
//  Buffer.hpp
//  ProducerConsumer
//
//  Created by Andrew Wei on 5/31/21.
//

#ifndef Buffer_hpp
#define Buffer_hpp

#include <mutex>
#include <condition_variable>
#include <stdio.h>
 
#define BUFFER_CAPACITY 10

class Buffer {
    // Buffer fields
    int buffer [BUFFER_CAPACITY];
    int buffer_size;
    int left; // index where variables are put inside of buffer (produced)
    int right; // index where variables are removed from buffer (consumed)
    
    // Fields for concurrency
    std::mutex mtx;
    std::condition_variable not_empty;
    std::condition_variable not_full;
    
public:
    // Place integer inside of buffer
    void produce(int thread_id, int num);
    
    // Remove integer from buffer
    int consume(int thread_id);
    
    Buffer();
};

#endif /* Buffer_hpp */
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Numerics.Discrete_Random;

package body pc_tasks is
   type Index_T is mod 10; -- Modular type for 10 values
   type Circular_Array is array (Index_T) of Integer;

   protected buffer is
      entry produce (Item : in Integer);
      entry consume (Item : out Integer);
   private
      Buf      : Circular_Array;
      P_Index  : Index_T := Index_T'First;
      C_Index  : Index_T := Index_T'First;
      Buf_Size : Natural := 0;
   end buffer;

   protected body buffer is
      entry produce (Item : in Integer) when Buf_Size < Index_T'Modulus is
      begin
         Buf (P_Index) := Item;
         P_Index       := P_Index + 1;
         Buf_Size      := Buf_Size + 1;
      end produce;

      entry consume (Item : out Integer) when Buf_Size > 0 is
      begin
         Item     := Buf (C_Index);
         C_Index  := C_Index + 1;
         Buf_Size := Buf_Size - 1;
      end consume;
   end buffer;

   task body produce_Int is
      subtype decimal is Integer range 1 .. 10;
      package rand_int is new Ada.Numerics.Discrete_Random (decimal);
      use rand_int;
      value : decimal;
      seed  : Generator;
   begin
      Reset (seed);
      for I in 1 .. 4 loop
         value := Random (seed);
         buffer.produce (value);
         Put_Line ("Task" & Id'Image & " produced" & value'Image);
         delay 0.1;
      end loop;
   end produce_Int;

   task body consume_Int is
      Num : Integer;
   begin
      for I in 1 .. 6 loop
         buffer.consume (Num);
         Put_Line ("Task" & Id'Image & " consumed" & Num'Image);
         delay 0.1;
      end loop;
   end consume_Int;

end pc_tasks;
//
//  Buffer.cpp
//  ProducerConsumer
//
//  Created by Andrew Wei on 5/31/21.
//

#include <iostream>
#include "Buffer.hpp"

Buffer::Buffer() {
    buffer_size = 0;
    left = 0;
    right = 0;
}

void Buffer::produce(int thread_id, int num) {
    // Acquire a unique lock on the mutex
    std::unique_lock<std::mutex> unique_lock(mtx);
    
    std::cout << "thread " << thread_id << " produced " << num << "\n";
    
    // Wait if the buffer is full
    not_full.wait(unique_lock, [this]() {
        return buffer_size != BUFFER_CAPACITY;
    });
    
    // Add input to buffer
    buffer[right] = num;
    
    // Update appropriate fields
    right = (right + 1) % BUFFER_CAPACITY;
    buffer_size++;
    
    // Unlock unique lock
    unique_lock.unlock();
    
    // Notify a single thread that buffer isn't empty
    not_empty.notify_one();
}

int Buffer::consume(int thread_id) {
    // Acquire a unique lock on the mutex
    std::unique_lock<std::mutex> unique_lock(mtx);
    
    // Wait if buffer is empty
    not_empty.wait(unique_lock, [this]() {
        return buffer_size != 0;
    });
    
    // Getvalue from position to remove in buffer
    int result = buffer[left];
    
    std::cout << "thread " << thread_id << " consumed " << result << "\n";
    
    // Update appropriate fields
    left = (left + 1) % BUFFER_CAPACITY;
    buffer_size--;
    
    // Unlock unique lock
    unique_lock.unlock();
    
    // Notify a single thread that the buffer isn't full
    not_full.notify_one();
    
    // Return result
    return result;
}
with pc_tasks;    use pc_tasks;
with Ada.Text_IO; use Ada.Text_IO;

procedure Main is
begin
   Put_Line("Executing code in main...");
   declare
      Produce_Task0 : produce_Int (0);
      Consume_Task0 : consume_Int (1);
      Produce_Task1 : produce_Int (2);
      Consume_Task1 : consume_Int (3);
      Produce_Task2 : produce_Int (4);
   begin
      null;
   end;
   Put_Line ("Done!");
end Main;
//
//  main.cpp
//  ProducerConsumer
//
//  Created by Andrew Wei on 5/30/21.
//

#include <thread>
#include <iostream>
#include "Buffer.hpp"
#include <stdlib.h>

// Takes in reference to a buffer and adds a random integer
void produceInt(Buffer &buffer) {
    for (int i = 0; i < 4; i++) {
        // Generate random number between 1 and 10
        int new_int = rand() % 10 + 1;
        buffer.produce(i, new_int);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

// Takes in reference to a buffer and returns the latest int added
// in the buffer
void consumeInt(Buffer &buffer) {
    for (int i = 0; i < 6; i++) {
        buffer.consume(i);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

int main(int argc, const char * argv[]) {
    std::cout << "Executing code in main...\n";
    
    // Initialize random seed
    srand (time(NULL));
    
    // Create Buffer
    Buffer buffer;
    
    // Create a thread to produce
    std::thread produceThread0(produceInt, std::ref(buffer));
    
    std::thread consumeThread0(consumeInt, std::ref(buffer));
    
    std::thread produceThread1(produceInt, std::ref(buffer));
    
    std::thread consumeThread1(consumeInt, std::ref(buffer));
    
    std::thread produceThread2(produceInt, std::ref(buffer));
    
    produceThread0.join();
    produceThread1.join();
    produceThread2.join();
    consumeThread0.join();
    consumeThread1.join();
    
    std::cout << "Done!\n";
    return 0;
}

 Summary

The same producer-consumer problem can be solved using both Ada and C++. The C++ approach to the producer-consumer pattern requires far more attention to low level details than does the Ada approach to the producer-consumer pattern. The greatest difference in the two approaches is the requirement for the C++ programmer to explicitly manipulate mutex locking/unlocking and suspended thread wait and notification commanding.

  • 15 October 2023 at 22:53

Bridge returned error 500! (19645)

15 October 2023 at 04:06

Details

Type: HttpException
Code: 500
Message: https://groups.google.com/g/comp.lang.ada resulted in 500 Internal Server Error
File: lib/contents.php
Line: 106

Trace

#0 index.php(11): RssBridge->main()
#1 lib/RssBridge.php(113): DisplayAction->execute()
#2 actions/DisplayAction.php(71): DisplayAction->createResponse()
#3 actions/DisplayAction.php(106): XPathAbstract->collectData()
#4 lib/XPathAbstract.php(406): GoogleGroupsBridge->provideWebsiteContent()
#5 bridges/GoogleGroupsBridge.php(56): getContents()
#6 lib/contents.php(106)

Context

Query: action=display&bridge=GoogleGroupsBridge&group=comp.lang.ada&account=&format=Atom
Version: 2023-09-24
OS: Linux
PHP: 8.2.7

Go back

No maintainer

  • 15 October 2023 at 04:06

[ANN] Release of UXStrings 0.6.0

This Ada library provides Unicode character strings of dynamic length.

It is now available on Alire in version 0.6.0.

Changes:

  • Add string convenient subprograms: Contains, Ends_With, Starts_With, Is_Lower, Is_Upper, Is_Basic, Is_Empty, Remove, Replace.
  • Add list of strings with convenient subprograms: Append_Unique, Filter, Join, Remove_Duplicates, Replace, Slice, Sort, Is_Sorted, Merge and Split on strings.

So far in UXStrings, its API are similar to those of the strings Ada standard libraries. If you find some missing, make your proposals on Github.

NB: UXStrings3 is now the default implementation.

submitted by /u/Blady-com
[link] [comments]
❌
❌