Home > other >  what is the "preferred" way of having threads use a variable calculated and updated by ano
what is the "preferred" way of having threads use a variable calculated and updated by ano

Time:08-08

I have a variable. That variable will only ever be calculated by one continuously running thread, others will be able to access it but not adjust it in any way. The other threads will not cooperate with each other, so it doesn't matter whether one of the other thread thinks that a = 3 and other that a = 2. Here is a simple non-working example that demostrates what I mean:

number = 0

def thread_target():
    while True:
        global number
        number = random.randint(1,60)

def thread_target2():
    global number
    for i in range(10):
        print(number)
        sleep(1)

t1 = Thread(target=thread_target)
t2 = Thread(target=thread_target2())
t1.start()
t2.start()
t2.join()

What is the "intended" tool/syntax for having something like this work?

CodePudding user response:

This problem can be satisfied using a producer-consumer pattern with a single element buffer. The producer writes a new value as often as it needs to. The consumers read the value in the buffer without modifying it whenever they need to.

As stated in https://sworthodoxy.blogspot.com/2015/05/shared-resource-design-patterns.html, which describes a solution to the problem using an Ada protected object,

Unconditional Buffer

A single element buffer without any access barrier is used when the reading task only needs to sample data from the writing task. If the reading task executes faster than the writing task, the reading task will read the same value more than once. If the writing task executes faster than the reading task some values will be skipped. Unconditional buffers are often used when sampling sensor data. Sensor data may be delivered to a program at a rate many times faster than it can be analyzed. The unconditional buffer simplifies the communication between the task reading from the sensor and the task analyzing the sensor data.

   protected type Read_Any_Buffer is
      procedure Put(Item : in Element_Type);
      function Get return Element_Type;
      function Initialized return Boolean;
   private
      Value    : Element_Type;
      Is_Valid : Boolean := False;
   end Read_Any_Buffer;

One issue with an unconditional buffer is determining if it contains valid data. It is unreasonable for the reading task to read uninitialized data. The function initialized can be polled to determine when the unconditional buffer has been initialized. After that happens the reading task merely calls the Get function whenever it wants access to the current value in the buffer. protected body Read_Any_Buffer is procedure Put(Item : in Element_Type) is begin Value := Item; Is_Valid := True; end Put;

  function Get return Element_Type is
  begin
     if not Is_Valid then
        raise Uninitialized_Data;
     end if;
     return Value;
  end Get;

  function Initialized return Boolean is
  begin
     return Is_Valid;
  end Initialized;

end Read_Any_Buffer; This example has the Get function raise the exception Uninitialized_Data if the function is called before data is initialized. The exception logic was placed in this function for safety only. It is much more efficient to poll the Initialized function than to iteratively handle exceptions.

CodePudding user response:

As i know, we can't do this directly but we can use property() function decorator that anyone should not access the data without using the getter and setter method.

You can read how to use property() function in this link

from time import sleep
import threading
import random

class Number:
    def __init__(self,number):
        """
        _number is private, anyone should not acces this variable
        without getter and setter method
        """
        self._number = number 

    @property
    def value(self):
        return self._number

    @value.setter
    def value(self,arg):
        if threading.current_thread().name=="Setter_thread":
            self._number = arg
        else:
            print("you have no permission")

number = Number(0)

def thread_target():
    while True:
       number.value=random.randint(1,60)
       sleep(1)

def thread_target2():
    for i in range(5):
        print(number.value)
        sleep(1)
    number.value=99 # will no effect
    print(number.value)

t1 = threading.Thread(target=thread_target,name="Setter_thread")
t2 = threading.Thread(target=thread_target2)
t1.start()
t2.start()
t1.join()
t2.join()
  • Related