Welcome to the new FlexRadio Community! Please review the new Community Rules and other important new Community information on the Message Board.
If you are having a problem, please refer to the product documentation or check the Help Center for known solutions.
Need technical support from FlexRadio? It's as simple as Creating a HelpDesk ticket.

SDR API Atomic Operations

Asher - K0AU
Asher - K0AU Member ✭✭
edited June 2020 in SmartSDR API
Enjoying working with the .NET API.  I understand radio operations are asynchronous, but not sure how everything is scheduled.  Take a code snippet like the example below.  Is the iterator safe?  Is it guaranteed to see the new slice?  Just trying to figure out if I need my own shadow structures to represent radio state and/or if I need to lock them.

Radio _radio;  // gets set through the API callback

Slice s = radio.CreateSlice(pan, demodMode, freq);
s.RequestSliceFromRadio();

foreach(Slice s in _radio.SliceList) {
   s.interestingExtensionAction(a, b, c);
}



Answers

  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    I am guessing that will be likely fine Asher. You will initiate action on n slices but you fill finish the initiation prior to acknowledgement of the last action, perhaps. I say perhaps because of the randomness of responses. Each request to the radio is pinned with an id. Each response has an id which is matched to the request id where finishing updates can be done. The difference between sendMessage and sendReplyMessage. the replies are asynchronous to the requests. You'd have to look at each specific ReplyHandle action to see if that generates an event for the display or just marks the object as stable. I think what you don't want to do is perform any action on an object that is 'in flight' in other words, pending success status returned from the radio. Doing that would be bad.
  • K9DUR
    K9DUR Member ✭✭
    edited January 2017

    Asher,

    Capture the "SliceAdded" event to be certain the slice has been added before you go through the iteration.

    73, Ray, K9DUR

  • Peter K1PGV
    Peter K1PGV Member ✭✭✭
    edited June 2020

    Hmmm....  This is a very good question.  Very good indeed!

    SliceList is a C# List. C# Lists are not intrinsically thread-safe for... anything, really.  That's why I'm *very* surprised to see FlexLib full of code like you've listed, with no locking.

    There is absolutely no guarantee that while you're enumerating the list, another entry won't be added... or that the entry that you've just retrieved won't be removed (and thus, invalid).

    Consider what happens when you're enumerating the list and another thread updates it at the same time.

    Now, maybe there's something intrinsic in the structure of FlexLib that we should know about that ensures that this List is only updated (and enumerated) by the same thread.  But, barring that, I don't see how any of the operations on SliceList in FlexLib can be thread safe.

    Peter
    K1PGV

  • Mark_W3II
    Mark_W3II Member ✭✭✭
    edited February 2018
    The convention is to lock the collection before enumeration. lock(radio.SliceList) { Use collection } Keep your loop very short / efficient otherwise create your own collection of objects and watch for events and check for valid object. Without the lock you will / may get collection has changed exceptions.
  • Asher - K0AU
    Asher - K0AU Member ✭✭
    edited March 2020
    Thanks for the input.  I'm not a C# programmer and I've only dabbled in Java/J2EE.  Would the lock be best practice or would creating my own event queue and service thread to serialize API event handlers and my UI events be a best practice? 

    BTW is there a better place for .NET FlexLib API discussion?  This is a bit arcane for the general forum.
  • James Whiteway
    edited April 2015
    It shows in both the API forum and the main forum. james WD5GWY
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    I believe that's why they invented the API forum.
  • Peter K1PGV
    Peter K1PGV Member ✭✭✭
    edited June 2020
    You asked:

    I'm not a C# programmer and I've only dabbled in Java/J2EE. Would the lock be best practice or would creating my own event queue and service thread to serialize API event handlers and my UI events be a best practice?

    Well, the thing is, FlexLib is spinning multiple threads underneath you to do various things. So, I'd rather hear from the devs (if they're willing to comment) on why they believe enumerating through SliceList without holding a lock is safe. Because it's done in multiple places in FlexLib. When they want to add or remove from the private _slices they take out the lock. But I don't see them holding the lock through plain enumerations such as doing searches. And I don't see how this can be thread safe. And requiring consumers to acquire an arbitrary type of lock on a returned property to serialize access to the underlying private field isn't best programming practice.

    Peter
    K1PGV
  • Asher - K0AU
    Asher - K0AU Member ✭✭
    edited June 2020
    Peter - Thanks for the heads up - now I have to study the FlexLib code a bit.  Perhaps the developers can comment on what's thread safe when multiple API clients are running.  My short-term goal is to write domain-specific control to augment the SSDR client.  But some of the operations end up touching two or three slices and pans and assume things like if I step through a list and move the next slice to "Active" that the slice will still be there.

    Would be nice to know if a snippet like above or like this that's setting fields is safe with a lock when a second client is running (there's more error checking to deal with empty lists and no active slice on the list).  The hazard is that I find an active slice and then the list grows or shrinks on a different thread so the incremented index doesn't point to the right thing.

    If it's not safe then what triggers a thread schedule?  Is it a preemptive time slice, any API call, an API call that triggers a wire interaction with the radio?  Probably enough questions for one day.

    int i = 0;
    foreach(Slice s in _slices.ActiveList)
      if (s.Active) i = s.Index;

    ++i;
    if (i ==_slices.ActiveList.Count()) i = 0;
    _slices.ActiveList.ElementAt(i).Active = true;


  • rfoust
    rfoust Member ✭✭
    edited December 2016
    Interesting, so that must be why I kept getting "modified collection" errors when calling RadioList.  I ended up working around it by using a for() loop.

    Starting at line 55 here:  https://github.com/rfoust/FlexModule/blob/master/FlexRadio.ps1
  • Mark_W3II
    Mark_W3II Member ✭✭✭
    edited February 2018
    I had correspondence with Eric on this very subject a short time ago, I ran across usage of the collection within the SDK that did not have thread protection. He informed me that he would address in the next release. As far as protection for a collection a common approach is to create an instance of Object to use for locking of a collection. In this way you can replace the collection object itself if you so desire. Since the collection is updated and not recreated locking occurs on the collection object itself. The truly beautiful thing is the API / SDK is supplied with full source code so there is complete transparency. Note the active slice can be found using the radio's Active Slice property. Also don't confuse the next slice in the collection with the slice index. Slice C is index 2 so you may have 2 slices in the collection and they are not necessarily index 0 and 1 ( A and B). I am in Cancun so back to the bar.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    I think though Peter, in the absence of anything Eric could add, is up until recently they were the only ones adding slices so, while not tight, in their use case it would be benign. There are lots of places Eric does use locks.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    Asher, I thought in your first snippet you were modifying the collection. If you aren't modifying the collection your iterator is fine. A second client gets their own universe, FlexLib is not shared so if you have two apps SSDR and yours, there would be no interaction.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    Wait, you interrupted your libation to type that post? What? do the drinks in Cancun ****?
  • Peter K1PGV
    Peter K1PGV Member ✭✭✭
    edited December 2016
    Well, that's true only if you can guarantee that all adds, removes, AND enumerations of the List are done in exactly the same (one single) thread. Is that likely?
  • Peter K1PGV
    Peter K1PGV Member ✭✭✭
    edited December 2016
    Actually, no. He's not safe even iterating the collection. Consider what happens when he's iterating through the collection while another thread removes an entry. Oops!
  • N7BCP
    N7BCP Member ✭✭
    edited November 2016
    If you can't protect against the list changing then make a copy and work with that.
  • Mark_W3II
    Mark_W3II Member ✭✭✭
    edited April 2015
    If you don't take breaks then the floor will interrupt the libations. The food and drink is most excellent. I suggested also to create your own collection however you must watch for slices deletion events so without knowing the entire use case locking is the most expedient.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    @Larry, that's what Java does, they have a CopyOnWriteList. When is list is rarely modified this is less expensive than a lock for, what turns out to be, no apparent reason.
  • Walt - KZ1F
    Walt - KZ1F Member ✭✭
    edited November 2016
    @Mark, I am impressed! I believe you got the whole bar thing totally nailed.

Leave a Comment

Rich Text Editor. To edit a paragraph's style, hit tab to get to the paragraph menu. From there you will be able to pick one style. Nothing defaults to paragraph. An inline formatting menu will show up when you select text. Hit tab to get into that menu. Some elements, such as rich link embeds, images, loading indicators, and error messages may get inserted into the editor. You may navigate to these using the arrow keys inside of the editor and delete them with the delete or backspace key.