Resource Opening

Hi everyone,

It is known that resources are opened in parallel, which is handled by opentap. However, is there a way we can bypass this such that certain instruments open/close in sequence?

I believe it can be done using instruments for stacked resources. But we dont really need a specific order, we just need to run in sequence.

Hi @antonio.quizon,

Just to understand the problem a bit better, why do you need them to open in a sequence rather than in parallel?

1 Like

Its not a strict requirement as of now, but just want to explore our current options. Currently, we are investigating a situation where an instrument and another instrument are using a shared library or driver which does not allow them to be accessed in parallel. In this case, we want to check if its possible to open them in sequence in the first place.

It also does not make sense to make it stacked, because there could be a scenario where I only use instrument A and not instrument B, and vice versa.

Got it.

If there is a non-thread-safe resource, you should lock that using a mutex or ‘monitor’ in C#.

e.g

class SafeApi{
    static object lockObject = new object();
    // public / safe API
    public static void SafeCall()
    {
        lock(lockObject) {
            UnsafeCall();
        }
    } 

   // Not safe. Dont make this public!
    void UnsafeCall(){
          // ...
    }

}

There is no problem locking our resources to be thread-safe . The problem is when a driver is being shared by 2 resources/instruments and this driver library is not under our control e.g. windows assemblies or third party libraries and cannot be changed to be thread-safe. What is then the alternative?

So you mean, you have a 3rd party OpenTAP plugin using an unsafe resource? And you want to use the same resource in your plugin?

It sounds like your 2 instruments uses the same driver, so at least they can lock the access between them to make that safe. I don’t understand which part of the system is not under your control.

Just for it to be a bit clearer, let me provide an example.

public class InstrumentA : Instrument{
    static object lockObject = new object();
      public void Open(){
      lock(lockObject) {
                  InstrumentADriver.Open(); ) // The drivers A and B have a common resource that cannot be used in parallel. And these drivers could be from external vendors.
              }
}
}

public class InstrumentB : Instrument{
    static object lockObject = new object();
      public void Open(){
      lock(lockObject) {
                  InstrumentBDriver.Open() // The drivers A and B have a common resource that cannot be used in parallel. And these drivers could be from external vendors.
              }
}
}

In this case, yes I can make the instruments A and instruments B be thread-safe within the same instances, but between A and B instances, is there a way I can make it sequential or thread-safe aside from creating a common lock?

Creating a common lock is the way you should do it.

Otherwise you can force them to be sequential by e.g referencing InstrumentA from InstrumentB.
It would be possible to make a Mixin which allows you to add the reference dynamically instead of at compile time.

There is no way you can specify the order directly, something would have to be changed inside OpenTAP for that to work.

Could you share more about this mixin approach?

I will share some info here, but I need a bit of time to put together the example.

1 Like

So here is the code for the mixin. You can get a feeling about how it works in the screenshots further down.

    // This mixin builder can be used on test steps or resources.
    [MixinBuilder(typeof(IResource), typeof(ITestStep))]
    [Display("Resource")]
    public class ResourceMixinBuilder : ValidatingObject, IMixinBuilder
    {
        public enum Type
        {
            Instrument,
            Dut,
            [Display("Result Listener")]
            ResultListener
        }
        
        static System.Type EnumToType(Type type)
        {
            switch (type)
            {
                case Type.Instrument: return typeof(IInstrument);
                case Type.Dut: return typeof(IDut);
                case Type.ResultListener: return typeof(IResultListener);
            }
            throw new InvalidOperationException("Unknown enum type: " + type);
        }
        
        public string Name { get; set; } = "Other Resource";
        public ResourceOpenBehavior Behavior { get; set; }
        [Display("Type")]
        public Type ResourceType { get; set; }
        public ResourceMixinBuilder()
        {
            
        }
        
        public void Initialize(ITypeData targetType)
        {
            
        }
        
        public MixinMemberData ToDynamicMember(ITypeData targetType)
        {
            return new MixinMemberData(this, () => null)
            {
                TypeDescriptor = TypeData.FromType(EnumToType(ResourceType)),
                Attributes = GetAttributes().ToArray(),
                Writable = true,
                Readable = true,
                DeclaringType = targetType,
                Name = "Resource." + Name 
            };
        }
        
        IEnumerable<Attribute> GetAttributes()
        {
            yield return new DisplayAttribute(Name, Order: 19999);
            yield return new ResourceOpenAttribute(Behavior);
        }
    }

First, right click on your resource (E.g InstrumentB) and select Add Mixin…

image

Finally you have a resource dependency inside your resource:

When this relationship is established, it guarantees that e.g SCPI1 is opened before SCPI2 (Depending on your selecting in Behavior).

Just want to add a side note. It is also possible to change the resource open/close strategy so e.g. resources are only opened when they are actually being used by a teststep and then closed again. It is an OpenTAP engine setting. Also available in the UI of KS8400.