o
    ?e@                     @   s
  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 deddZdd Zdd Zdd Ze Zdd Zejdd ZedG dd dZ dS )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CriticalSectionZcritical_sectionsZcritical_section_executionsc                   @   s   e Zd ZdZdS )_ExecutionSignaturezGA class storing an `ExecuteInCriticalResource` op and associated attrs.N)__name__
__module____qualname____doc__ r   r   k/home/www/facesmatcher.com/pyenv/lib/python3.10/site-packages/tensorflow/python/ops/critical_section_ops.pyr   )   s    r   ophandle	resourcesexclusive_resource_accessc                 C   sH   t | tjr
|  S t | tjrt| S t	 r| du rdS t
| S )zEIdentity op that recognizes `TensorArray`, `Operation`, and `Tensor`.N)
isinstancer   ZTensorArrayidentityr   Z	Operationr   groupr   executing_eagerlyr   )xr   r   r   	_identity1   s   

r   c                 C   s   | j pt| S N)device_get_colocationr   r   r   r   _get_device_or_colocation=   s   r#   c              	   C   s&   z|  dW S  ttfy   Y dS w )z&Get colocation symbol from op, if any._classN)get_attr
ValueErrorAttributeErrorr"   r   r   r   r!   A   s
   r!   c                   C   s(   zt jW S  ty   g t _t j Y S w r   )_CRITICAL_SECTION_STACKvaluer'   r   r   r   r   _get_critical_section_stackL   s   
r*   c                 c   s    t  }| |v rtd|  d||  zdV  W | }|| kr,td|  d| dS | }|| kr@td|  d| 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 )r*   r&   appendpopRuntimeError)	signaturestackZreceived_signaturer   r   r   _push_critical_section_stackT   s8   

r0   c                   @   sT   e Zd ZdZ		dddZdd Zedd Zdd
dZdd Z	dd Z
dd ZdS )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                 C   sF   t   |r|durtd| d| d|rtd| || dS )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   Zensure_initializedr&   _init_from_args)selfnameshared_nameZcritical_section_defZimport_scoper   r   r   __init__   s   

zCriticalSection.__init__c              	   C   s   t |dg D}t  0 t  j}|du r|}|du rd}tj|||d| _||p.t| jt	| jf| _
W d   n1 s?w   Y  W d   n1 sNw   Y  t s_t t|  dS dS )z:Initialize the CriticalSection from constructor arguments.r   N )r4   	containerr3   )r   
name_scopeZ
init_scopeget_default_graph
_containerr   Zmutex_v2_handleidr#   
_signaturer   r   add_to_collectionsCRITICAL_SECTIONS)r2   r3   r4   r7   r   r   r   r1      s(   

zCriticalSection._init_from_argsc                 C   s
   | j jjS r   )r;   r   r3   r2   r   r   r   r3      s   
zCriticalSection.nameTc                    s|  t |dg + t jk t j}t sYt 	 j
2 t 	  }t |g | }W d   n1 s9w   Y  tt 	  |}W d   n1 sSw   Y  nt |g | }W d   n1 smw   Y  W d   n1 s|w   Y  t s ||j tdd |D }t fdd|D rtd j d || d	d t|D }	t |	/ t  j t|}
W d   n1 sw   Y  t|tt|}W d   n1 sw   Y  t |
g tt|}W d   n	1 sw   Y  t s*t|j jt ||d
}t !t"| |W  d   S 1 s7w   Y  dS )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.
    Zcritical_section_executeNc                 S   s(   g | ]}|j D ]
}|jtjkr|qqS r   )inputsZdtyper   resource.0r   input_r   r   r   
<listcomp>!  s    
z+CriticalSection.execute.<locals>.<listcomp>c                 3   s    | ]}  |V  qd S r   )_is_self_handlerD   r   r@   r   r   	<genexpr>+      z*CriticalSection.execute.<locals>.<genexpr>zPAttempting to lock a CriticalSection in which we are already running (signature=z+). This is illegal and may cause deadlocks.c                 S   s   g | ]}t |qS r   )r   rH   r   r   r   rF   4  s    r   )#r   r8   r0   r=   r   Z
mutex_lockr;   r   r   r9   _lockZget_operationsZcontrol_dependenciesset
difference!_add_control_dependencies_to_lockr   r
   ZObjectIdentitySetanyr&   #_check_multiple_access_to_resourcesr	   flattenZcolocate_withZconsume_mutex_lockZpack_sequence_asr   tupleZmap_structurer   r   listr>   CRITICAL_SECTION_EXECUTIONS)r2   fnr   r3   lockZexisting_opsrcreated_opscaptured_resourcesZr_flatZensure_lock_existsZoutputsr.   r   r@   r   execute   sr   


	
&zCriticalSection.executec                 C   s   t dd |D }|dd |D  tdd |D }|D ]	}||jd q|jD ]	}||jd q+|jD ]
}||jjd q8||jd | }|sRdS t	j
| }|| dS )z=To avoid deadlocks, all args must be executed before lock_op.c                 S   s   g | ]}|j D ]}|jqqS r   )rA   r   rC   r   r   r   rF   T  s    zECriticalSection._add_control_dependencies_to_lock.<locals>.<listcomp>c                 s   s     | ]}|j D ]}|V  qqd S r   )control_inputs)rD   r   Zinput_opr   r   r   rI   U  s    zDCriticalSection._add_control_dependencies_to_lock.<locals>.<genexpr>c                 s   s    | ]}|j |fV  qd S r   )_id)rD   r   r   r   r   rI   \  rJ   N)rL   updatedictr,   r\   r[   rA   r   valuesr   r   Z_add_control_input)r2   rX   Zlock_opall_argsZall_args_dictr   rE   r   r   r   rN   Q  s"   



z1CriticalSection._add_control_dependencies_to_lockc                 C   sp   t |tjr|| ju S |jjdko7|jdo7|jd| jjdko7|jj| jjjkp7t|jt| jjkS )z<Check if the tensor `x` is the same Mutex as `self._handle`.ZMutexV2r4   )	r   r   ZEagerTensorr;   r   typer%   r    r!   )r2   r   r   r   r   rG   w  s   


zCriticalSection._is_self_handlec                 C   sh   t tD ],}| |jrq|s|jsq||j}|r1tdt	| d| j
 d| d|j d	qdS )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   Zget_collectionrT   rG   r   r   intersectionr   r&   rS   r;   )r2   rY   r   ZsgZresource_intersectionr   r   r   rP     s(   
z3CriticalSection._check_multiple_access_to_resources)NNNN)TN)r   r   r   r   r5   r1   propertyr3   rZ   rN   rG   rP   r   r   r   r   r   y   s    D


j&)!r   collections
contextlib	threadingZtensorflow.python.eagerr   Ztensorflow.python.frameworkr   r   Ztensorflow.python.opsr   r   r   r   Ztensorflow.python.utilr	   r
   Z tensorflow.python.util.tf_exportr   __all__r?   rT   
namedtupler   r   r#   r!   localr(   r*   contextmanagerr0   r   r   r   r   r   <module>   s>   

$