
    AVh@                     f   d Z ddlZddlZddlZddlmZ ddlmZ ddlmZ ddl	m
Z
 ddl	mZ ddl	mZ dd	l	mZ dd
lmZ ddlmZ ddlmZ dgZdZdZ G d d ej,                  dd            Zd Zd Zd Z ej6                         Zd Zej<                  d        Z ed       G d d             Z y)z,Critical Section object and execution logic.    N)context)dtypes)ops)	array_ops)control_flow_ops)gen_resource_variable_ops)tensor_array_ops)nest)object_identity)	tf_exportCriticalSectioncritical_sectionscritical_section_executionsc                       e Zd ZdZy)_ExecutionSignaturezGA class storing an `ExecuteInCriticalResource` op and associated attrs.N)__name__
__module____qualname____doc__     Z/home/dcms/DCMS/lib/python3.12/site-packages/tensorflow/python/ops/critical_section_ops.pyr   r   )   s     Pr   r   ophandle	resourcesexclusive_resource_accessc                    t        | t        j                        r| j                         S t        | t        j
                        rt        j                  |       S t        j                         r| yt        j                  |       S )zEIdentity op that recognizes `TensorArray`, `Operation`, and `Tensor`.N)
isinstancer	   TensorArrayidentityr   	Operationr   groupr   executing_eagerlyr   )xs    r   	_identityr&   1   sb    #//0::<!S]]#!!!$$  "qya  r   c                 4    | j                   xs t        |       S N)device_get_colocationr   s    r   _get_device_or_colocationr,   =   s    		)ob))r   c                 P    	 | j                  d      S # t        t        f$ r Y yw xY w)z&Get colocation symbol from op, if any._classN)get_attr
ValueErrorAttributeErrorr+   s    r   r*   r*   A   s-    ;;x  
n	% s    %%c                  x    	 t         j                  S # t        $ r g t         _        t         j                  cY S w xY wr(   )_CRITICAL_SECTION_STACKvaluer1   r   r   r   _get_critical_section_stackr5   L   s7    )"(((	 )$&!"((()s    $99c              #     K   t               }| |v rt        d|  d      |j                  |        	 d |j                         }|| k7  rt	        d|  d|       y# |j                         }|| k7  rt	        d|  d|       w xY ww)a  Push a CriticalSection._signature to the thread-local stack.

  If the signature is already on the stack, raise an error because it means
  we're trying to execute inside the same locked CriticalSection, which
  will create a deadlock.

  Args:
    signature: Tuple of the type `CriticalSection._signature`.  Uniquely
      identifies a CriticalSection by its `shared_name`, `container`,
      and device.

  Yields:
    An empty value.  The context is guaranteed to run without deadlock.

  Raises:
    ValueError: If the signature is already on the stack.
    RuntimeError: If another thread or function modifies the current stack
      entry during the yield.
  z0Attempting to lock a CriticalSection (signature=zK) in which we are already running. This is illegal and may cause deadlocks.Nz8CriticalSection stack inconsistency: expected signature z but received )r5   r0   appendpopRuntimeError)	signaturestackreceived_signatures      r   _push_critical_section_stackr=   T   s     * &
'%%

:9+ FL 	LM M ,,y<	Y&
DK~&8%9;< < ' Y&
DK~&8%9;< < 's   /BA 'B(BBc                   L    e Zd ZdZ	 	 d
dZd Zed        ZddZd Z	d Z
d	 Zy)r   a#	  Critical section.

  A `CriticalSection` object is a resource in the graph which executes subgraphs
  in **serial** order.  A common example of a subgraph one may wish to run
  exclusively is the one given by the following function:

  ```python
  v = resource_variable_ops.ResourceVariable(0.0, name="v")

  def count():
    value = v.read_value()
    with tf.control_dependencies([value]):
      with tf.control_dependencies([v.assign_add(1)]):
        return tf.identity(value)
  ```

  Here, a snapshot of `v` is captured in `value`; and then `v` is updated.
  The snapshot value is returned.

  If multiple workers or threads all execute `count` in parallel, there is no
  guarantee that access to the variable `v` is atomic at any point within
  any thread's calculation of `count`.  In fact, even implementing an atomic
  counter that guarantees that the user will see each value `0, 1, ...,` is
  currently impossible.

  The solution is to ensure any access to the underlying resource `v` is
  only processed through a critical section:

  ```python
  cs = CriticalSection()
  f1 = cs.execute(count)
  f2 = cs.execute(count)
  output = f1 + f2
  session.run(output)
  ```
  The functions `f1` and `f2` will be executed serially, and updates to `v`
  will be atomic.

  **NOTES**

  All resource objects, including the critical section and any captured
  variables of functions executed on that critical section, will be
  colocated to the same device (host and cpu/gpu).

  When using multiple critical sections on the same resources, there is no
  guarantee of exclusive access to those resources.  This behavior is disallowed
  by default (but see the kwarg `exclusive_resource_access`).

  For example, running the same function in two separate critical sections
  will not ensure serial execution:

  ```python
  v = tf.compat.v1.get_variable("v", initializer=0.0, use_resource=True)
  def accumulate(up):
    x = v.read_value()
    with tf.control_dependencies([x]):
      with tf.control_dependencies([v.assign_add(up)]):
        return tf.identity(x)
  ex1 = CriticalSection().execute(
    accumulate, 1.0, exclusive_resource_access=False)
  ex2 = CriticalSection().execute(
    accumulate, 1.0, exclusive_resource_access=False)
  bad_sum = ex1 + ex2
  sess.run(v.initializer)
  sess.run(bad_sum)  # May return 0.0
  ```
  Nc                     t        j                          |r|t        d| d| d      |rt        d      | j                  ||       y)zCreates a critical section.NzArguments critical_section_def=z and shared_name=z9 are mutually exclusive. Please only specify one of them.z1Argument `critical_section_def` is not supported.)r   ensure_initializedr0   _init_from_args)selfnameshared_namecritical_section_defimport_scopes        r   __init__zCriticalSection.__init__   sd       089M8N O**5 7:: ; ; JKK
4-r   c                    t        j                  |dg       5 }t        j                         5  t        j                         j                  }||}|d}t        j                  |||      | _        ||xs t        | j                        t        | j                        f| _
        ddd       ddd       t        j                         st        j                  t        |        yy# 1 sw Y   AxY w# 1 sw Y   ExY w)z:Initialize the CriticalSection from constructor arguments.r   N )rD   	containerrC   )r   
name_scope
init_scopeget_default_graph
_containerr   mutex_v2_handleidr,   
_signaturer   r$   add_to_collectionsCRITICAL_SECTIONS)rB   rC   rD   rJ   s       r   rA   zCriticalSection._init_from_args   s    	/	4 5>> 5))+66	+)099#ytE +2dll+%dll3	555$ $$&	.5 '#5 55 5s#   C1A8C%%C1%C.	*C11C:c                 B    | j                   j                  j                  S r(   )rP   r   rC   )rB   s    r   rC   zCriticalSection.name   s    <<??r   c           
          t        j                  |dg       5  t         j                        5  t	        j
                   j                        }t        j                         st        j                         j                  5  t        j                         j                         }t        j                  |g      5   |       }ddd       t        t        j                         j                               j                  |      }ddd       n&t        j                  |g      5   |       }ddd       ddd       t        j                         s j                  j                          t#        j$                  |D 	cg c]2  }|j&                  D ]!  }	|	j(                  t*        j,                  k(  r|	# 4 c}	}      }
t/         fd|
D              rt1        d j                   d       j3                  |
|       t5        j6                        D cg c]  }t9        |       }}t        j                  |      5  t        j:                   j                        5  t	        j<                        }ddd       t5        j>                  |tA        jB                  t5        j6                  |                  }ddd       t        j                  g      5  t5        jD                  t8        |      }ddd       t        j                         sFtG        j                    j                  tI        
      |      }t        jJ                  tL        |       cddd       S # 1 sw Y   xY w# 1 sw Y   AxY w# 1 sw Y   NxY w# 1 sw Y   SxY wc c}	}w c c}w # 1 sw Y   +xY w# 1 sw Y   xY w# 1 sw Y   xY w# 1 sw Y   yxY w)a  Execute function `fn()` inside the critical section.

    `fn` should not accept any arguments.  To add extra arguments to when
    calling `fn` in the critical section, create a lambda:

    ```python
    critical_section.execute(lambda: fn(*my_args, **my_kwargs))
    ```

    Args:
      fn: The function to execute.  Must return at least one tensor.
      exclusive_resource_access: Whether the resources required by
        `fn` should be exclusive to this `CriticalSection`.  Default: `True`.
        You may want to set this to `False` if you will be accessing a
        resource in read-only mode in two different CriticalSections.
      name: The name to use when creating the execute operation.

    Returns:
      The tensors returned from `fn()`.

    Raises:
      ValueError: If `fn` attempts to lock this `CriticalSection` in any nested
        or lazy way that may cause a deadlock.
      ValueError: If `exclusive_resource_access == True` and
        another `CriticalSection` has an execution requesting the same
        resources as `fn``.  Note, even if `exclusive_resource_access` is
        `True`, if another execution in another `CriticalSection` was created
        without `exclusive_resource_access=True`, a `ValueError` will be raised.
    critical_section_executeNc              3   @   K   | ]  }j                  |        y wr(   )_is_self_handle).0r%   rB   s     r   	<genexpr>z*CriticalSection.execute.<locals>.<genexpr>+  s     C1t##A&Cs   zPAttempting to lock a CriticalSection in which we are already running (signature=z+). This is illegal and may cause deadlocks.r   )'r   rK   r=   rR   r   
mutex_lockrP   r   r$   rM   _lockget_operationscontrol_dependenciesset
difference!_add_control_dependencies_to_lockr   r   ObjectIdentitySetinputsdtyper   resourceanyr0   #_check_multiple_access_to_resourcesr
   flattenr&   colocate_withconsume_mutex_lockpack_sequence_asr   tuplemap_structurer   listrS   CRITICAL_SECTION_EXECUTIONS)rB   fnr   rC   lockexisting_opsrcreated_opsr   input_captured_resourcesr%   r_flatensure_lock_existsoutputsr:   s   `               r   executezCriticalSection.execute   sF   < 
8"	= J (8 (33DLLA((* $$&,, 6002AACL))4&1 $a
 s446EEGH&J|4 6 6 ''/ A!& &&(..{DGGD
 ->>(@
))@
||v. @
@
  C0BCC,,0OO+< =))* *
 	00 9	; '+ll1o6	!6f6##F+ Nt||, 	  9KK 
		 !!!%5%;%;DLLO%LMN ##%7$89 3$$Y23 &&('ww<<-.&?	A	
 	'	4 UJ J 6 6 ! 2@
& 7	 	N N3 3}J Js   OAN9M*:M	AM*N#M7+N3AO?7N6AON&O= N)N3AN)7ON50A#OM'"M**M4/N7N<NN		ON&!N))N2	.O5N>	:OO
c                    t        |D cg c]  }|j                  D ]  }|j                   ! c}}      }|j                  d |D               t	        d |D              }|D ]  }|j                  |j                  d         |j                  D ]  }|j                  |j                  d         |j                  D ](  }|j                  |j                  j                  d       * |j                  |j                  d       |j                         }|syt        j                  | }|j                  |       yc c}}w )z=To avoid deadlocks, all args must be executed before lock_op.c              3   B   K   | ]  }|j                   D ]  }|   y wr(   )control_inputs)rZ   r   input_ops      r   r[   zDCriticalSection._add_control_dependencies_to_lock.<locals>.<genexpr>U  s1      Jr7H7HJ+3JJs   c              3   8   K   | ]  }|j                   |f  y wr(   )_id)rZ   r   s     r   r[   zDCriticalSection._add_control_dependencies_to_lock.<locals>.<genexpr>\  s     9""&&"9s   N)r`   rd   r   updatedictr8   r   r~   valuesr   r#   _add_control_input)rB   ru   lock_opr   rv   all_argsall_args_dicts          r   rb   z1CriticalSection._add_control_dependencies_to_lockQ  s#    L""))LFIILILMHOO J&J J 999M  &%&$$ &%&.. -		t,-gkk4(##%H  %%x0Hx(A Ms   $D;
c                 $   t        |t        j                        r|| j                  u S |j                  j
                  dk(  xr |j                  j                  d      xr |j                  j                  d      | j                  j                  j                  d      k(  xrn |j                  j                  | j                  j                  j                  k(  xs5 t        |j                        t        | j                  j                        k(  S )z<Check if the tensor `x` is the same Mutex as `self._handle`.MutexV2rD   )	r   r   EagerTensorrP   r   typer/   r)   r*   )rB   r%   s     r   rY   zCriticalSection._is_self_handlew  s    !S__%$,,DDII" Om,O }-))-89O
  6 66 N#ADD)_T\\__-MMPr   c                 :   t        j                  t              D ]  }| j                  |j                        r|s|j
                  s.|j                  |j                        }|sLt        dt        |       d| j                   d| d|j                   d	       y)a  Raise if captured_resources are accessed by another CriticalSection.

    Args:
      captured_resources: Set of tensors of type resource.
      exclusive_resource_access: Whether this execution requires exclusive
        resource access.

    Raises:
      ValueError: If any tensors in `captured_resources` are also accessed
        by another `CriticalSection`, and at least one of them requires
        exclusive resource access.
    z'This execution would access resources: z%. Either this lock (CriticalSection: z) or lock 'z' (CriticalSection: z) requested exclusive resource access of this resource. Did you mean to call execute with keyword argument exclusive_resource_access=False?N)r   get_collectionrp   rY   r   r   intersectionr   r0   ro   rP   )rB   rw   r   sgresource_intersections        r   rh   z3CriticalSection._check_multiple_access_to_resources  s    "   !<= A			bii	('2+G+G0==bllK	5)*+ ,!!%k" >!!# ,@@A 	AAr   )NNNN)TN)r   r   r   r   rG   rA   propertyrC   r{   rb   rY   rh   r   r   r   r   r   y   sH    BH -17;.6.    hT#)L
P Ar   )!r   collections
contextlib	threadingtensorflow.python.eagerr   tensorflow.python.frameworkr   r   tensorflow.python.opsr   r   r   r	   tensorflow.python.utilr
   r    tensorflow.python.util.tf_exportr   __all__rT   rp   
namedtupler   r&   r,   r*   localr3   r5   contextmanagerr=   r   r   r   r   <module>r      s    3    + . + + 2 ; 2 ' 2 6 
 ( ; K0FG	!* *)//+ ) !< !<H iA iA iAr   