The AF SDK is designed to be used in high performance applications where multiple execution threads are used to improve overall throughput. AF SDK also uses multiple threads internally in some cases to improve performance. This section discusses how AF SDK should be called in a multithreaded application to ensure proper operation.
In AF SDK, objects are automatically loaded and initialized when they are accessed. There are also many calls to load objects in bulk. To make these calls easy to use in a multithreaded environment, AF SDK manages thread safety for read operations. Read operations like loading objects, accessing collections, reading object properties, and querying time-series data can be done concurrently on multiple threads without callers synchronizing access.
AF SDK does not ensure thread safety for write operations; serializing access to objects during modification is the responsibility of the caller. Write operations are usually performed over multiple steps so the caller is in the best position to know when an operation is complete. An AF object should not be modified on multiple threads simultaneously, nor should it be read while being modified on another thread. It is safe to modify different objects simultaneously. In addition to editing the properties of an object, editing one of its collections, checking in, checking out, or refreshing all constitute write operations on an object and should not be done simultaneously.
AF SDK uses background tasks to complete some actions. Methods that could result in executing a background task are noted in the documentation for the method. The .NET runtime automatically flows the ExecutionContext when executing a background task. The ExecutionContext encapsulates the SynchronizationContext, the SecurityContext, and the CallContext. In general, background tasks run seemlessly and callers do not need to be aware of them. However, there are some circumstances where the caller's ExecutionContext can interact with AF SDK background tasks to cause issues.
AF SDK is designed to work in multi-user environments with impersonated threads (e.g. an ASP.NET web application). Each PISystems and PIServers instance and all objects associated with those collections are linked to the identity of the user who created them. Connections used to access each PISystem or PIServer are cached and subsequent calls are validated to ensure they are only accessed by the owning identity. Thus care should be taken to only use objects from threads running under the same identity that created them.
Another complication can arise when impersonating while calling AF SDK methods that use background tasks. AF SDK relies on the .NET runtime flowing the SecurityContext across asynchronous points to ensure that calls are made using the correct identity. When impersonation is done with the WindowsIdentityImpersonate method, the identity is installed in the SecurityContext and background tasks will run with the correct identity. However, if impersonation is done from native code, the impersonated identity will not be installed in the SecurityContext and background tasks will run with the identity of the process, potentially leading to errors. To configure the SecurityContext correctly, either impersonate using WindowsIdentityImpersonate or enable the alwaysFlowImpersonationPolicy option in the application's runtime settings.
AF SDK will not attempt to execute tasks on the caller's SynchronizationContext (e.g. the Dispatcher when called from a UI application). AF SDK will schedule background tasks to run on the task scheduler defined by TaskSchedulerCurrent. Because AF SDK needs the background tasks it runs to complete before it returns to the caller, the caller should not use AF SDK methods that do background work from a task scheduler that cannot schedule and execute the background tasks before the AF SDK method completes.