By introducing a request pattern in the loop approach, it may be possible to resolve many of the issues with the update of components in the loop approach: who is updating who, how to ensure data is available in the correct order, and how to avoid infinite loops or dead-locks.

This idea has not been analyzed for implications to the standard. Take a look at it, and evaluate whether you thing this is a suitable approach.

Please add comments for any issues that is not yet considered in this approach.

The idea is that in a loop approach one component is not allowed to update another one. It can send a requst for data for an exchange item, and if data is available, it can get the data. If data is not available, the source component will record the request. When the source component at some later stage is updated, it will check which requests now have data available and send that.

An example of an update of a component

  public class ComponentA
  {
    /// <summary>
    /// True if request for data has been send out
    /// </summary>
    private bool _hasSendRequests = false;
    
    /// <summary>
    /// List of items that needs to be exchanged in each time steup
    /// </summary>
    private List<IExchangeItem> ActiveItems;

    /// <summary>
    /// List of items in ActiveItems that have not yet been updated
    /// </summary>
    private List<IExchangeItem> PendingActiveItems;

    /// <summary>
    /// List of items that other linkable components have requested data for, 
    /// i.e., which is in the other linkable components PendingActiveItems list
    /// </summary>
    private List<IExchangeItem> IncomingRequests;


    /// <summary>
    /// Update the component, returns true if updated, false if not updated
    /// </summary>
    /// <param name="forceUpdate">Force the component to update always</param>
    public bool Update(bool forceUpdate)
    {
      // Check if we have already send out requests for active items for this timestep.
      if (!_hasSendRequests)
      {
        // We have not send requests, send a request for data for each active item
        foreach (IExchangeItem item in ActiveItems)
        {
          // Send request, see if data is already available
          // If data is not available, the other component registers this item in its list of IncomingRequests
          bool dataIsReady = SendRequestForData(item);
          if (dataIsReady)
          {
            // Data is ready, transfer data
            TransferDataFor(item);
          } 
          else 
          {
            // Data is not ready, put it in pending list
            PendingActiveItems.Add(item);
          }
        }
        _hasSendRequests = true;
      }

      // If this is a forced update, get the best possible data for each pending active item
      if (forceUpdate)
      {
        foreach (IExchangeItem item in PendingActiveItems)
        {
          GetBestPossibleDataFor(item);
        }
        PendingActiveItems.Clear();
      }

      // If we have pending active items, we can not update the component
      if (PendingActiveItems.Count > 0)
        return (false);

      // No pending active items, we can update component to next timestep.
      DoUpdateComponent();

      // Check each incoming request, whether data is now available
      foreach (IExchangeItem item in IncomingRequests)
      {
        if (DataIsAvaiableFor(item))
        {
          // Data is now available for this item, send data to component. 
          // The other component must remove item from its PendingActiveItems
          TransferDataFor(item);
          IncomingRequests.Remove(item);
        }
      }
      return (true);
    }

  }

The driving routine can then just loop over all components and update the one with least progress in time

    public void RunAll(List<ILinkableComponent> components)
    {
      // Check if all components has finised
      while(!AllFinished(components))
      {
        // Sort the components such that the one have least progress in time is first
        SortBySmallestModelTime(components);

        // bool checking if a component updated successfully
        bool updatedOneCompenent = false;

        // Run one timestep for one component, try them in order of least progress in time
        foreach (ILinkableComponent component in components)
        {
          bool success = component.Update();
          if (success)
          {
            updatedOneCompenent = true;
            break;
          }
        }

        // No component updated successfully, force the first component to update
        if (!updatedOneCompenent)
        {
          components[0].Update(true);
        }
      }
    }

  • No labels