I have tried using shared memory for strings with the following simple Python code, and it works well.
from multiprocessing import Value, Array, Process, Lock
def process1(array, lock):
with lock:
buffer_data = str("z1111").encode("utf-8")
array[0:len(buffer_data)] = buffer_data[:]
if __name__ == '__main__':
array = Array('c', 35)
lock = Lock()
process_test1 = Process(target=process1, args=[array, lock], daemon=True)
process_test1.start()
process_test1.join()
print(array[:].decode("utf-8"))
print("process ended")
Next, I tried implementing shared memory for numbers using a GUI library called Kivy, and that worked well too.
from multiprocessing import Process, Value, set_start_method, freeze_support, Lock
kvLoadString=("""
<TextWidget>:
BoxLayout:
orientation: 'vertical'
size: root.size
Button:
id: button1
text: "start"
font_size: 48
on_press: root.buttonClicked()
Label:
id: lab
text: 'result'
""")
def start_process(count,lock):
process_test = Process(target=p_test, args=[count,lock], daemon=True)
process_test.start()
return process_test
def p_test(count,lock):
i = 0
while True:
print(i)
i = i + 1
with lock:
count.value = i
if __name__ == '__main__':
freeze_support()
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.checkbox import CheckBox
from kivy.uix.spinner import Spinner
from kivy.properties import StringProperty,NumericProperty,ObjectProperty, BooleanProperty
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.treeview import TreeView, TreeViewLabel, TreeViewNode
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.progressbar import ProgressBar
from kivy.uix.button import Button
set_start_method('spawn')
class TestApp(App):
def __init__(self, **kwargs):
super(TestApp, self).__init__(**kwargs)
self.title = 'testApp'
def build(self):
return TextWidget()
class TextWidget(Widget):
def __init__(self, **kwargs):
super(TextWidget, self).__init__(**kwargs)
self.process_test = None
self.proc = None
# shared memory
self.count = Value('i', 0)
self.lock = Lock()
def buttonClicked(self):
if self.ids.button1.text == "start":
self.proc = start_process(self.count,self.lock)
self.ids.button1.text = "stop"
else:
if self.proc:
self.proc.kill()
self.ids.button1.text = "start"
self.ids.lab.text = str(self.count.value)
Builder.load_string(kvLoadString)
TestApp().run()
However, I did not succeed in using Kivy with shared memory for strings as follows.
from multiprocessing import Array,Process, Value, set_start_method, freeze_support, Lock
import math
kvLoadString=("""
<TextWidget>:
BoxLayout:
orientation: 'vertical'
size: root.size
Button:
id: button1
text: "start"
font_size: 48
on_press: root.buttonClicked()
Label:
id: lab
text: 'result'
""")
def start_process(array,lock):
process_test = Process(target=p_test, args=[array,lock], daemon=True)
process_test.start()
return process_test
def p_test(array,lock):
with lock:
buffer_data = str("z1111").encode("utf-8")
array[0:len(buffer_data)] = buffer_data[:]
print(array.decode("utf-8"))
if __name__ == '__main__':
freeze_support()
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.checkbox import CheckBox
from kivy.uix.spinner import Spinner
from kivy.properties import StringProperty,NumericProperty,ObjectProperty, BooleanProperty
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.treeview import TreeView, TreeViewLabel, TreeViewNode
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.progressbar import ProgressBar
from kivy.uix.button import Button
set_start_method('spawn')
class TestApp(App):
def __init__(self, **kwargs):
super(TestApp, self).__init__(**kwargs)
self.title = 'testApp'
def build(self):
return TextWidget()
class TextWidget(Widget):
def __init__(self, **kwargs):
super(TextWidget, self).__init__(**kwargs)
self.process_test = None
self.proc = None
# shared memory
self.array = Array('c', 35)
self.lock = Lock()
def buttonClicked(self):
if self.ids.button1.text == "start":
self.proc = start_process(self.array,self.lock)
self.ids.button1.text = "stop"
else:
if self.proc:
self.proc.kill()
self.ids.button1.text = "start"
self.ids.lab.text = self.array.decode("utf-8")
Builder.load_string(kvLoadString)
TestApp().run()
The error message is as follows. How can I avoid such an error?
Traceback (most recent call last):
File "C:\Users\taichi\Documents\Winpython64-3.9.10.0\WPy64-39100\python-3.9.10.amd64\lib\multiprocessing\process.py", line 315, in _bootstrap
self.run()
File "C:\Users\taichi\Documents\Winpython64-3.9.10.0\WPy64-39100\python-3.9.10.amd64\lib\multiprocessing\process.py", line 108, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\taichi\Desktop\test.py", line 29, in p_test
print(array.decode("utf-8"))
AttributeError: 'SynchronizedString' object has no attribute 'decode'
That was tricky, as it turned out it was not a kivy issue. Try the following to convert array or self.array into a string:
s = bytes.join(b'', [c for c in array if c != b'\x00']).decode('utf-8')