WorkQueue outstanding() race condition vs new task submission
**Describe the bug**
One of the users that I am supporting has encountered this:


2022-02-23 14:42:14 parsl.dataflow.flow_control:114 MainProcess(112424) FlowControl-Thread [ERROR]  Flow control callback threw an exception - logging and proceeding anyway
Traceback (most recent call last):
  File "REDACTED/wq_env/lib/python3.8/site-packages/parsl/dataflow/flow_control.py", line 112, in make_callback
    self.callback(tasks=self._event_buffer, kind=kind)
  File "REDACTED/wq_env/lib/python3.8/site-packages/parsl/dataflow/task_status_poller.py", line 104, in poll
    self._strategy.strategize(self._poll_items, tasks)
  File "REDACTED/wq_env/lib/python3.8/site-packages/parsl/dataflow/strategy.py", line 140, in _strategy_simple
    self._general_strategy(status_list, tasks, strategy_type='simple')
  File "REDACTED/wq_env/lib/python3.8/site-packages/parsl/dataflow/strategy.py", line 174, in _general_strategy
    active_tasks = executor.outstanding
  File "REDACTED/wq_env/lib/python3.8/site-packages/parsl/executors/workqueue/executor.py", line 633, in outstanding
    for fut in self.tasks.values():
RuntimeError: dictionary changed size during iteration
```

This happens repeatedly during execution under high job submission load, and looks like a race condition on both flow control and job submission trying to access the work queue executor's `self.tasks` structure.

Later on, the run does not actually successfully execute any jobs and work queue workers time out after a while. I am unclear if this is due to this error or something else.

**To Reproduce**
High job submission load with WQ.

**Expected behavior**
No exceptions.

**Distributed Environment**
desc parsl branch
diff --git a/parsl/executors/workqueue/executor.py b/parsl/executors/workqueue/executor.py
index 79c1ff4d..78646c0c 100644
--- a/parsl/executors/workqueue/executor.py
+++ b/parsl/executors/workqueue/executor.py
@@ -623,9 +623,10 @@ class WorkQueueExecutor(BlockProviderExecutor, putils.RepresentationMixin):
         implemented and probably could be replaced with a counter.
         """
         outstanding = 0
-        for fut in self.tasks.values():
-            if not fut.done():
-                outstanding += 1
+        with self.tasks_lock:
+            for fut in self.tasks.values():
+                if not fut.done():
+                    outstanding += 1
         logger.debug(f"Counted {outstanding} outstanding tasks")
         return outstanding
 
['parsl/executors/workqueue/executor.py']