We use ros-kinetic-dynamic-reconfigure 1.5.49-0xenial-20180316-113241-0800.
And occasionally rosrun dynamic_reconfigure dynparam load command reports error updating parameters: don't know parameter xxx. After spent some time to investigate the symptom, I think race condition exits in src/dynamic_reconfigure/client.py
168 def update_configuration(self, changes):
169 """
170 Change the server's configuration
171
172 @param changes: dictionary of key value pairs for the parameters that are changing
173 @type changes: {str: value}
174 """
175 # Retrieve the parameter descriptions
176 if self.param_description is None:
177 self.get_parameter_descriptions()
178
179 # Cast the parameters to the appropriate types
180 if self.param_description is not None:
181 for name, value in list(changes.items())[:]:
182 if name != 'groups':
183 dest_type = self._param_types.get(name)
184 if dest_type is None:
185 raise DynamicReconfigureParameterException('don\'t know parameter: %s' % name)
Line 185 "error updating parameters: don't know parameter xxx” is reported because the parameter xxx is not exist in map self._param_types.
From below code excerpt, we can see self._param_types is initialized after line 338 after self.param_description is extracted in line
331.
329 def _descriptions_msg(self, msg):
330 self.group_description = decode_description(msg)
331 self.param_description = extract_params(self.group_description)
332
333 # Build map from parameter name to type
334 self._param_types = {}
335 for p in self.param_description:
336 n, t = p.get('name'), p.get('type')
337 if n is not None and t is not None:
338 self._param_types[n] = self._param_type_from_string(t) <<---------
339
340 with self._cv:
341 self._cv.notifyAll()
342 if self._description_callback is not None:
343 self._description_callback(self.param_description)
Function get_parameter_descriptions will return after self.param_description is NOT None
121 def get_parameter_descriptions(self, timeout=None):
122 """
123 UNSTABLE. Return a description of the parameters for the server.
124 Do not use this method as the type that is returned may change.
125
126 @param timeout: time to wait before giving up
127 @type timeout: float
128 """
129 if timeout is None or timeout == 0.0:
130 with self._cv:
131 while self.param_description is None:
132 if rospy.is_shutdown():
133 return None
134 self._cv.wait()
135 else:
136 start_time = time.time()
137 with self._cv:
138 while self.param_description is None:
139 if rospy.is_shutdown():
140 return None
141 secs_left = timeout - (time.time() - start_time)
142 if secs_left <= 0.0:
143 break
144 self._cv.wait(secs_left)
145
146 return self.param_description
But self.param_description is NOT None doesn’t mean self._param_types is successfully initialized, if thread 1 is executing Line 333 ~338, some parameters maybe not set.
333 # Build map from parameter name to type
334 self._param_types = {}
335 for p in self.param_description:
336 n, t = p.get('name'), p.get('type')
337 if n is not None and t is not None:
338 self._param_types[n] = self._param_type_from_string(t)
Thread 2 execute line 183 will report error.
183 dest_type = self._param_types.get(name)
184 if dest_type is None:
185 raise DynamicReconfigureParameterException('don\'t know parameter: %s' % name)
Could we fix it by add self._param_types_inited to indicate whether self._param_types is already initialized
@@ -76,6 +76,7 @@
self.group_description = None
self._param_types = None
+ self._param_types_inited = False
self._cv = threading.Condition()
@@ -128,14 +129,14 @@
"""
if timeout is None or timeout == 0.0:
with self._cv:
- while self.param_description is None:
+ while self._param_types_inited is False:
if rospy.is_shutdown():
return None
self._cv.wait()
else:
start_time = time.time()
with self._cv:
- while self.param_description is None:
+ while self._param_types_inited is False:
if rospy.is_shutdown():
return None
secs_left = timeout - (time.time() - start_time)
@@ -337,6 +338,7 @@
if n is not None and t is not None:
self._param_types[n] = self._param_type_from_string(t)
+ self._param_types_inited = True
with self._cv:
self._cv.notifyAll()
if self._description_callback is not None:
We use
ros-kinetic-dynamic-reconfigure 1.5.49-0xenial-20180316-113241-0800
. And occasionallyrosrun dynamic_reconfigure dynparam load
command reportserror updating parameters: don't know parameter xxx
. After spent some time to investigate the symptom, I think race condition exits insrc/dynamic_reconfigure/client.py
Line 185 "error updating parameters: don't know parameter xxx” is reported because the parameter xxx is not exist in map self._param_types.
From below code excerpt, we can see self._param_types is initialized after line 338 after self.param_description is extracted in line
Function get_parameter_descriptions will return after self.param_description is NOT None
But self.param_description is NOT None doesn’t mean self._param_types is successfully initialized, if thread 1 is executing Line 333 ~338, some parameters maybe not set.
Thread 2 execute line 183 will report error.
Could we fix it by add self._param_types_inited to indicate whether self._param_types is already initialized