prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  callback_server.py example error
  <!--
  Please use the Pymodbus gitter channel at https://gitter.im/pymodbus_dev/Lobby or Stack Overflow(tag [pymodbus](https://stackoverflow.com/questions/tagged/pymodbus) for
  support questions.
  
  Before opening a new issue, make sure you do the following:
      * check that your issue isn't already filed: https://github.com/riptideio/pymodbus/issues
      * prepare a short, runnable example that reproduce the issue with the latest development version of Pymodbus
  -->
  
  ### Versions
  
  * Python: 3.7
  * OS: Ubuntu 20
  * Pymodbus: 2.5.0
  * Modbus Hardware (if used): 
  
  ### Pymodbus Specific
  * Server: rtu - sync
  * Client: rtu - sync
  
  ### Description
  
  When I adapt the "callback_server.py" example, I make the queue client modify the datastore, but my client doesn't see the changes.
  after some work, it's due to the use of Process creation for the queue listener that makes changes in it's own scope.
  
  ### Correction
  change the queue Process listener creation :
  ```python
      p = Process(target=device_writer, args=(queue,))
      p.start()
  ```
  by a Thread queue listenrer makes changes could be seen by my client because of modification made in the same server scope:
  ```python
  from threading import Thread
  ...
       t = Thread(target = device_writer, args=(queue,))
      t.start()
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `examples/common/callback_server.py`
  Content:
  ```
  1 #!/usr/bin/env python3
  2 # pylint: disable=missing-type-doc,missing-param-doc,differing-param-doc
  3 """Pymodbus Server With Callbacks.
  4 
  5 This is an example of adding callbacks to a running modbus server
  6 when a value is written to it. In order for this to work, it needs
  7 a device-mapping file.
  8 """
  9 import logging
  10 from multiprocessing import Queue, Process
  11 
  12 # --------------------------------------------------------------------------- #
  13 # import the modbus libraries we need
  14 # --------------------------------------------------------------------------- #
  15 from pymodbus.version import version
  16 from pymodbus.server.asynchronous import StartTcpServer
  17 from pymodbus.device import ModbusDeviceIdentification
  18 from pymodbus.datastore import ModbusSparseDataBlock
  19 from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
  20 
  21 # from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer
  22 
  23 
  24 # --------------------------------------------------------------------------- #
  25 # configure the service logging
  26 # --------------------------------------------------------------------------- #
  27 log = logging.getLogger()
  28 log.setLevel(logging.DEBUG)
  29 
  30 # --------------------------------------------------------------------------- #
  31 # create your custom data block with callbacks
  32 # --------------------------------------------------------------------------- #
  33 
  34 
  35 class CallbackDataBlock(ModbusSparseDataBlock):
  36     """A datablock that stores the new value in memory,
  37 
  38     and passes the operation to a message queue for further processing.
  39     """
  40 
  41     def __init__(self, devices, queue):
  42         """Initialize."""
  43         self.devices = devices
  44         self.queue = queue
  45 
  46         values = {k: 0 for k in devices.keys()}
  47         values[0xBEEF] = len(values)  # the number of devices
  48         super().__init__(values)
  49 
  50     def setValues(self, address, value):  # pylint: disable=arguments-differ
  51         """Set the requested values of the datastore
  52 
  53         :param address: The starting address
  54         :param values: The new values to be set
  55         """
  56         super().setValues(address, value)
  57         self.queue.put((self.devices.get(address, None), value))
  58 
  59 
  60 # --------------------------------------------------------------------------- #
  61 # define your callback process
  62 # --------------------------------------------------------------------------- #
  63 
  64 
  65 def rescale_value(value):
  66     """Rescale the input value from the range of 0..100 to -3200..3200.
  67 
  68     :param value: The input value to scale
  69     :returns: The rescaled value
  70     """
  71     scale = 1 if value >= 50 else -1
  72     cur = value if value < 50 else (value - 50)
  73     return scale * (cur * 64)
  74 
  75 
  76 def device_writer(queue):
  77     """Process new messages from a queue to write to device outputs
  78 
  79     :param queue: The queue to get new messages from
  80     """
  81     while True:
  82         device, value = queue.get()
  83         rescale_value(value[0])
  84         txt = f"Write({device}) = {value}"
  85         log.debug(txt)
  86         if not device:
  87             continue
  88         # do any logic here to update your devices
  89 
  90 
  91 # --------------------------------------------------------------------------- #
  92 # initialize your device map
  93 # --------------------------------------------------------------------------- #
  94 
  95 
  96 def read_device_map(path):
  97     """Read the device path to address mapping from file::
  98 
  99        0x0001,/dev/device1
  100        0x0002,/dev/device2
  101 
  102     :param path: The path to the input file
  103     :returns: The input mapping file
  104     """
  105     devices = {}
  106     with open(path, "r") as stream:  # pylint: disable=unspecified-encoding
  107         for line in stream:
  108             piece = line.strip().split(",")
  109             devices[int(piece[0], 16)] = piece[1]
  110     return devices
  111 
  112 
  113 def run_callback_server():
  114     """Run callback server."""
  115     # ----------------------------------------------------------------------- #
  116     # initialize your data store
  117     # ----------------------------------------------------------------------- #
  118     queue = Queue()
  119     devices = read_device_map("device-mapping")
  120     block = CallbackDataBlock(devices, queue)
  121     store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)
  122     context = ModbusServerContext(slaves=store, single=True)
  123 
  124     # ----------------------------------------------------------------------- #
  125     # initialize the server information
  126     # ----------------------------------------------------------------------- #
  127     identity = ModbusDeviceIdentification(
  128         info_name={
  129             "VendorName": "pymodbus",
  130             "ProductCode": "PM",
  131             "VendorUrl": "http://github.com/riptideio/pymodbus/",
  132             "ProductName": "pymodbus Server",
  133             "ModelName": "pymodbus Server",
  134             "MajorMinorRevision": version.short(),
  135         }
  136     )
  137 
  138     # ----------------------------------------------------------------------- #
  139     # run the server you want
  140     # ----------------------------------------------------------------------- #
  141     proc = Process(target=device_writer, args=(queue,))
  142     proc.start()
  143     StartTcpServer(context, identity=identity, address=("localhost", 5020))
  144 
  145 
  146 if __name__ == "__main__":
  147     run_callback_server()
  148
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/examples/common/callback_server.py b/examples/common/callback_server.py
  --- a/examples/common/callback_server.py
  +++ b/examples/common/callback_server.py
  @@ -7,7 +7,8 @@
   a device-mapping file.
   """
   import logging
  -from multiprocessing import Queue, Process
  +from multiprocessing import Queue
  +from threading import Thread
   
   # --------------------------------------------------------------------------- #
   # import the modbus libraries we need
  @@ -138,8 +139,8 @@
       # ----------------------------------------------------------------------- #
       # run the server you want
       # ----------------------------------------------------------------------- #
  -    proc = Process(target=device_writer, args=(queue,))
  -    proc.start()
  +    thread = Thread(target=device_writer, args=(queue,))
  +    thread.start()
       StartTcpServer(context, identity=identity, address=("localhost", 5020))
  
verification_info: {"golden_diff": "diff --git a/examples/common/callback_server.py b/examples/common/callback_server.py\n--- a/examples/common/callback_server.py\n+++ b/examples/common/callback_server.py\n@@ -7,7 +7,8 @@\n a device-mapping file.\n \"\"\"\n import logging\n-from multiprocessing import Queue, Process\n+from multiprocessing import Queue\n+from threading import Thread\n \n # --------------------------------------------------------------------------- #\n # import the modbus libraries we need\n@@ -138,8 +139,8 @@\n     # ----------------------------------------------------------------------- #\n     # run the server you want\n     # ----------------------------------------------------------------------- #\n-    proc = Process(target=device_writer, args=(queue,))\n-    proc.start()\n+    thread = Thread(target=device_writer, args=(queue,))\n+    thread.start()\n     StartTcpServer(context, identity=identity, address=(\"localhost\", 5020))\n", "issue": "callback_server.py example error\n<!--\r\nPlease use the Pymodbus gitter channel at https://gitter.im/pymodbus_dev/Lobby or Stack Overflow(tag [pymodbus](https://stackoverflow.com/questions/tagged/pymodbus) for\r\nsupport questions.\r\n\r\nBefore opening a new issue, make sure you do the following:\r\n    * check that your issue isn't already filed: https://github.com/riptideio/pymodbus/issues\r\n    * prepare a short, runnable example that reproduce the issue with the latest development version of Pymodbus\r\n-->\r\n\r\n### Versions\r\n\r\n* Python: 3.7\r\n* OS: Ubuntu 20\r\n* Pymodbus: 2.5.0\r\n* Modbus Hardware (if used): \r\n\r\n### Pymodbus Specific\r\n* Server: rtu - sync\r\n* Client: rtu - sync\r\n\r\n### Description\r\n\r\nWhen I adapt the \"callback_server.py\" example, I make the queue client modify the datastore, but my client doesn't see the changes.\r\nafter some work, it's due to the use of Process creation for the queue listener that makes changes in it's own scope.\r\n\r\n### Correction\r\nchange the queue Process listener creation :\r\n```python\r\n    p = Process(target=device_writer, args=(queue,))\r\n    p.start()\r\n```\r\nby a Thread queue listenrer makes changes could be seen by my client because of modification made in the same server scope:\r\n```python\r\nfrom threading import Thread\r\n...\r\n     t = Thread(target = device_writer, args=(queue,))\r\n    t.start()\r\n```\r\n\n", "before_files": [{"content": "#!/usr/bin/env python3\n# pylint: disable=missing-type-doc,missing-param-doc,differing-param-doc\n\"\"\"Pymodbus Server With Callbacks.\n\nThis is an example of adding callbacks to a running modbus server\nwhen a value is written to it. In order for this to work, it needs\na device-mapping file.\n\"\"\"\nimport logging\nfrom multiprocessing import Queue, Process\n\n# --------------------------------------------------------------------------- #\n# import the modbus libraries we need\n# --------------------------------------------------------------------------- #\nfrom pymodbus.version import version\nfrom pymodbus.server.asynchronous import StartTcpServer\nfrom pymodbus.device import ModbusDeviceIdentification\nfrom pymodbus.datastore import ModbusSparseDataBlock\nfrom pymodbus.datastore import ModbusSlaveContext, ModbusServerContext\n\n# from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer\n\n\n# --------------------------------------------------------------------------- #\n# configure the service logging\n# --------------------------------------------------------------------------- #\nlog = logging.getLogger()\nlog.setLevel(logging.DEBUG)\n\n# --------------------------------------------------------------------------- #\n# create your custom data block with callbacks\n# --------------------------------------------------------------------------- #\n\n\nclass CallbackDataBlock(ModbusSparseDataBlock):\n    \"\"\"A datablock that stores the new value in memory,\n\n    and passes the operation to a message queue for further processing.\n    \"\"\"\n\n    def __init__(self, devices, queue):\n        \"\"\"Initialize.\"\"\"\n        self.devices = devices\n        self.queue = queue\n\n        values = {k: 0 for k in devices.keys()}\n        values[0xBEEF] = len(values)  # the number of devices\n        super().__init__(values)\n\n    def setValues(self, address, value):  # pylint: disable=arguments-differ\n        \"\"\"Set the requested values of the datastore\n\n        :param address: The starting address\n        :param values: The new values to be set\n        \"\"\"\n        super().setValues(address, value)\n        self.queue.put((self.devices.get(address, None), value))\n\n\n# --------------------------------------------------------------------------- #\n# define your callback process\n# --------------------------------------------------------------------------- #\n\n\ndef rescale_value(value):\n    \"\"\"Rescale the input value from the range of 0..100 to -3200..3200.\n\n    :param value: The input value to scale\n    :returns: The rescaled value\n    \"\"\"\n    scale = 1 if value >= 50 else -1\n    cur = value if value < 50 else (value - 50)\n    return scale * (cur * 64)\n\n\ndef device_writer(queue):\n    \"\"\"Process new messages from a queue to write to device outputs\n\n    :param queue: The queue to get new messages from\n    \"\"\"\n    while True:\n        device, value = queue.get()\n        rescale_value(value[0])\n        txt = f\"Write({device}) = {value}\"\n        log.debug(txt)\n        if not device:\n            continue\n        # do any logic here to update your devices\n\n\n# --------------------------------------------------------------------------- #\n# initialize your device map\n# --------------------------------------------------------------------------- #\n\n\ndef read_device_map(path):\n    \"\"\"Read the device path to address mapping from file::\n\n       0x0001,/dev/device1\n       0x0002,/dev/device2\n\n    :param path: The path to the input file\n    :returns: The input mapping file\n    \"\"\"\n    devices = {}\n    with open(path, \"r\") as stream:  # pylint: disable=unspecified-encoding\n        for line in stream:\n            piece = line.strip().split(\",\")\n            devices[int(piece[0], 16)] = piece[1]\n    return devices\n\n\ndef run_callback_server():\n    \"\"\"Run callback server.\"\"\"\n    # ----------------------------------------------------------------------- #\n    # initialize your data store\n    # ----------------------------------------------------------------------- #\n    queue = Queue()\n    devices = read_device_map(\"device-mapping\")\n    block = CallbackDataBlock(devices, queue)\n    store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)\n    context = ModbusServerContext(slaves=store, single=True)\n\n    # ----------------------------------------------------------------------- #\n    # initialize the server information\n    # ----------------------------------------------------------------------- #\n    identity = ModbusDeviceIdentification(\n        info_name={\n            \"VendorName\": \"pymodbus\",\n            \"ProductCode\": \"PM\",\n            \"VendorUrl\": \"http://github.com/riptideio/pymodbus/\",\n            \"ProductName\": \"pymodbus Server\",\n            \"ModelName\": \"pymodbus Server\",\n            \"MajorMinorRevision\": version.short(),\n        }\n    )\n\n    # ----------------------------------------------------------------------- #\n    # run the server you want\n    # ----------------------------------------------------------------------- #\n    proc = Process(target=device_writer, args=(queue,))\n    proc.start()\n    StartTcpServer(context, identity=identity, address=(\"localhost\", 5020))\n\n\nif __name__ == \"__main__\":\n    run_callback_server()\n", "path": "examples/common/callback_server.py"}], "after_files": [{"content": "#!/usr/bin/env python3\n# pylint: disable=missing-type-doc,missing-param-doc,differing-param-doc\n\"\"\"Pymodbus Server With Callbacks.\n\nThis is an example of adding callbacks to a running modbus server\nwhen a value is written to it. In order for this to work, it needs\na device-mapping file.\n\"\"\"\nimport logging\nfrom multiprocessing import Queue\nfrom threading import Thread\n\n# --------------------------------------------------------------------------- #\n# import the modbus libraries we need\n# --------------------------------------------------------------------------- #\nfrom pymodbus.version import version\nfrom pymodbus.server.asynchronous import StartTcpServer\nfrom pymodbus.device import ModbusDeviceIdentification\nfrom pymodbus.datastore import ModbusSparseDataBlock\nfrom pymodbus.datastore import ModbusSlaveContext, ModbusServerContext\n\n# from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer\n\n\n# --------------------------------------------------------------------------- #\n# configure the service logging\n# --------------------------------------------------------------------------- #\nlog = logging.getLogger()\nlog.setLevel(logging.DEBUG)\n\n# --------------------------------------------------------------------------- #\n# create your custom data block with callbacks\n# --------------------------------------------------------------------------- #\n\n\nclass CallbackDataBlock(ModbusSparseDataBlock):\n    \"\"\"A datablock that stores the new value in memory,\n\n    and passes the operation to a message queue for further processing.\n    \"\"\"\n\n    def __init__(self, devices, queue):\n        \"\"\"Initialize.\"\"\"\n        self.devices = devices\n        self.queue = queue\n\n        values = {k: 0 for k in devices.keys()}\n        values[0xBEEF] = len(values)  # the number of devices\n        super().__init__(values)\n\n    def setValues(self, address, value):  # pylint: disable=arguments-differ\n        \"\"\"Set the requested values of the datastore\n\n        :param address: The starting address\n        :param values: The new values to be set\n        \"\"\"\n        super().setValues(address, value)\n        self.queue.put((self.devices.get(address, None), value))\n\n\n# --------------------------------------------------------------------------- #\n# define your callback process\n# --------------------------------------------------------------------------- #\n\n\ndef rescale_value(value):\n    \"\"\"Rescale the input value from the range of 0..100 to -3200..3200.\n\n    :param value: The input value to scale\n    :returns: The rescaled value\n    \"\"\"\n    scale = 1 if value >= 50 else -1\n    cur = value if value < 50 else (value - 50)\n    return scale * (cur * 64)\n\n\ndef device_writer(queue):\n    \"\"\"Process new messages from a queue to write to device outputs\n\n    :param queue: The queue to get new messages from\n    \"\"\"\n    while True:\n        device, value = queue.get()\n        rescale_value(value[0])\n        txt = f\"Write({device}) = {value}\"\n        log.debug(txt)\n        if not device:\n            continue\n        # do any logic here to update your devices\n\n\n# --------------------------------------------------------------------------- #\n# initialize your device map\n# --------------------------------------------------------------------------- #\n\n\ndef read_device_map(path):\n    \"\"\"Read the device path to address mapping from file::\n\n       0x0001,/dev/device1\n       0x0002,/dev/device2\n\n    :param path: The path to the input file\n    :returns: The input mapping file\n    \"\"\"\n    devices = {}\n    with open(path, \"r\") as stream:  # pylint: disable=unspecified-encoding\n        for line in stream:\n            piece = line.strip().split(\",\")\n            devices[int(piece[0], 16)] = piece[1]\n    return devices\n\n\ndef run_callback_server():\n    \"\"\"Run callback server.\"\"\"\n    # ----------------------------------------------------------------------- #\n    # initialize your data store\n    # ----------------------------------------------------------------------- #\n    queue = Queue()\n    devices = read_device_map(\"device-mapping\")\n    block = CallbackDataBlock(devices, queue)\n    store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)\n    context = ModbusServerContext(slaves=store, single=True)\n\n    # ----------------------------------------------------------------------- #\n    # initialize the server information\n    # ----------------------------------------------------------------------- #\n    identity = ModbusDeviceIdentification(\n        info_name={\n            \"VendorName\": \"pymodbus\",\n            \"ProductCode\": \"PM\",\n            \"VendorUrl\": \"http://github.com/riptideio/pymodbus/\",\n            \"ProductName\": \"pymodbus Server\",\n            \"ModelName\": \"pymodbus Server\",\n            \"MajorMinorRevision\": version.short(),\n        }\n    )\n\n    # ----------------------------------------------------------------------- #\n    # run the server you want\n    # ----------------------------------------------------------------------- #\n    thread = Thread(target=device_writer, args=(queue,))\n    thread.start()\n    StartTcpServer(context, identity=identity, address=(\"localhost\", 5020))\n\n\nif __name__ == \"__main__\":\n    run_callback_server()\n", "path": "examples/common/callback_server.py"}]}