Dispose DataReader with DataAvailable event in C#

3 posts / 0 new
Last post
Offline
Last seen: 3 weeks 4 days ago
Joined: 04/05/2022
Posts: 3
Dispose DataReader with DataAvailable event in C#

Dear community,

I'm using the .net connector with RTI DDS 6.1.0.3 under Linux/WSL with .net 6  (the issue is the same in .net 5). My goal is to read the data published from dynamic_data_using_publisher_subscriber example and exit gracefully. The issue I'm facing, is that during Dispose I get an exception: PRESPsService_destroyLocalEndpoint:!delete local reader

My code is the following: 

using Rti.Dds.Domain;
using Rti.Dds.Subscription;
using Rti.Dds.Topics;
using Rti.Types.Dynamic;
DomainParticipant participant = DomainParticipantFactory.Instance.CreateParticipant(0);
DynamicType BuildShapeType()
{
  var factory = DynamicTypeFactory.Instance;
  return factory.BuildStruct()
    .WithName("ShapeType")
    .AddMember(new StructMember("color", factory.CreateString(128), isKey: true))
    .AddMember(new StructMember("x", factory.GetPrimitiveType<int>()))
    .AddMember(new StructMember("y", factory.GetPrimitiveType<int>()))
    .AddMember(new StructMember("shapesize", factory.GetPrimitiveType<int>()))
    .Create();
}
Topic<DynamicData> topic = participant.CreateTopic("Square", BuildShapeType());
Subscriber subscriber = participant.CreateSubscriber();
DataReader<DynamicData> reader = subscriber.CreateDataReader(topic);
reader.DataAvailable += OnDataAvailable;
void OnDataAvailable(AnyDataReader _)
{
  foreach (var sample in reader.Take())
    if (sample.Info.ValidData) Console.WriteLine(sample.Data);
    else Console.WriteLine($"Instance state changed to: {sample.Info.State.Instance}");
}
ManualResetEvent blocker = new(false);
Console.CancelKeyPress += OnCancelKeyPress;
void OnCancelKeyPress(object? sender, ConsoleCancelEventArgs e)
{
  e.Cancel = true;
  blocker.Set();
}
blocker.WaitOne();
reader.DataAvailable -= OnDataAvailable;
Console.CancelKeyPress -= OnCancelKeyPress;
participant.Dispose();

I start this application, then the dynamic_data_using_publisher_subscriber example. The samples are received and displayed. I stop the publisher, then I press ctrl+c to trigger the ManualResetEvent and finish my application. Exception is displayed.

This is the output: 

color: "BLUE"
x: 50
y: 100
shapesize: 30

 [...]

color: "BLUE"
x: 80
y: 100
shapesize: 45

Instance state changed to: NotAliveNoWriters
^C[0x0101E606,0xAAF52FA4,0x0213F34E:0x80000009{E=Su,D=0}|DELETE DR WITH TOPIC Square] PRESPsService_destroyLocalEndpoint:!delete local reader
[0x0101E606,0xAAF52FA4,0x0213F34E:0x80000009{E=Su,D=0}|DELETE DR WITH TOPIC Square] DDS_DataReader_deleteI:!delete PRESLocalEndpoint
[0x0101E606,0xAAF52FA4,0x0213F34E:0x80000009{E=Su,D=0}|DELETE DR WITH TOPIC Square] DDS_Subscriber_delete_datareader:!delete reader
Unhandled exception. Omg.Dds.Core.PreconditionNotMetException: DDS error stack:
[0x0101E606,0xAAF52FA4,0x0213F34E:0x80000009{E=Su,D=0}|DELETE DR WITH TOPIC Square] PRESPsService_destroyLocalEndpoint:!delete local reader
[0x0101E606,0xAAF52FA4,0x0213F34E:0x80000009{E=Su,D=0}|DELETE DR WITH TOPIC Square] DDS_DataReader_deleteI:!delete PRESLocalEndpoint
[0x0101E606,0xAAF52FA4,0x0213F34E:0x80000009{E=Su,D=0}|DELETE DR WITH TOPIC Square] DDS_Subscriber_delete_datareader:!delete reader

at Rti.Dds.NativeInterface.Helpers.ReturnCode.CheckResult(DDS_ReturnCode_t retcode)
at Rti.Dds.NativeInterface.Core.NativeStorageMethods.DestroyManagedObject(INativeStorage self, IntPtr nativeEntity, Func`2 deleteAction, Boolean throwOnError)
at Rti.Dds.NativeInterface.Core.NativeEntity.DestroyEntity(IntPtr nativeEntity, Func`2 deleteAction)
at Rti.Dds.NativeInterface.Subscription.NativeDataReader.DeleteNative(IntPtr reader)
at Rti.Dds.NativeInterface.Subscription.NativeDataReader.Dispose(Boolean freeManagedResources)
at Rti.Dds.NativeInterface.Core.NativeEntity.Dispose()
at Rti.Dds.Core.Entity.Dispose(Boolean disposing)
at Rti.Dds.Subscription.AnyDataReader.Dispose(Boolean closing)
at Rti.Dds.Subscription.Subscriber.DisposeContainedEntities()
at Rti.Dds.Subscription.Subscriber.Dispose(Boolean closing)
at Rti.Dds.Domain.DomainParticipant.DisposeContainedEntities()
at Rti.Dds.Domain.DomainParticipant.Dispose(Boolean disposing)
at Rti.Dds.Core.Entity.Dispose()
at Program.<Main>$(String[] args) in /home/z001x91h/repos/local/datareadertest/Program.cs:line 51

My question is: What am I doing wrong?

Thank you,

 Andras

 

Organization:
Offline
Last seen: 2 weeks 5 days ago
Joined: 04/02/2013
Posts: 179

The issue seems to be here:

 

foreach(var sample inreader.Take())

 

The collection of LoanedSamples returned by Read/Take must be returned to the middleware by disposing it (for ex. with the "using" keyword):

using var samples = reader.Take()

foreach (var sample in samples)

 

See https://community.rti.com/static/documentation/connext-dds/current/doc/api/connext_dds/api_csharp/class_rti_1_1_dds_1_1_subscription_1_1_loaned_samples.html

Offline
Last seen: 3 weeks 4 days ago
Joined: 04/05/2022
Posts: 3

Thank you! It is working now!