Best ways to create unique coroutine task

I am wandering, how to create coroutines, that’ll be running one in time. Make one, that’ll set bool ‘isRuning’ and if running on start - break immediately - is easy. In this case first coroutine will be unique:

private bool _isRunning;
private IEnumerable RunMe()
{
    if (_isRunning) yield break;
    _isRunning = true;

    while (something)
    {
        //do stuff;
        yield return null;
    }
    _isRunning = false;
}

but what if I want to create coroutine, that’ll break if another started?

or another case: coroutine, that’ll run itself only when previous is finished (so them will run one by one in queue)?

How to create generic approach for such cases (in static class as an extension, for instance)?

Typically what I do is save the Coroutine to a handle and if the handle != null then that means the Coroutine is still running.

here is an example script using my typical strategy of handling a Coroutine that should only run one at a time. I use a Property to manage a Coroutine that should only have one running instance per script. and if a Coroutine is already running then it stops the currently running Coroutine and then sets the new Coroutine to it, which will usually either restart the coroutine or stop it. In this example you can stun the gameobject for a determined amount of seconds. and if a second stun is called before the first one completes the second stun will override the first if its longer than the remaining stun.

public class StunnableScript:MonoBehaviour
{
    //you can have some Entities with varying resistances to a stun, 
    // reducing or increasing the duration of the stun
    public float stunResistance=1;

    //backing variable for the stunHandle
    private Coroutine _stunHandle;
    
    
    
    public void Stun(float _stunDuration)
    {
        _stunDuration = _stunDuration*stunResistance;
        //if the previous stun is longer than the new stun then do nothing
        if(stunDuration >_stunDuration)
            return;

        StunHandle = StartCoroutine(StunRoutine(_stunDuration));
    }


    public float stunDuration {get;private set;}

    private Coroutine StunHandle 
    { 
        get{ return _stunHandle; }
        set
        {
            if(_stunHandle!=null)
                StopCoroutine(_stunHandle);
            
            _stunHandle=value;
        } 
    }


    private IEnumerator StunRoutine(float _stunDuration)
    {
        stunDuration = _stunDuration;

        //you could have used WaitForSeconds, but this allows 
        // you to give real-time feedback of how much stun duration is left
        // that a GUI element can refer to.
        while (stunDuration>0) 
        {
            stunDuration -= Time.deltaTime;
            yield return null;
        }
        StunHandle = null;
    }
}

For your second case of having a second coroutine run after a first is completed, you can instead have one coroutine yeild to another.

  IEnumerator RunFirst()
  {
      while(thingsAreTrue)
      {
          //do stuff
          yield return null;
      }
    
      yield return StartCoroutine(RunSecond());
  }

  IEnumerator RunSecond()
  {
      while(OtherthingsAreTrue)
      {
          //do stuff
          yield return null;
      }
  }