SetString (Subsystem function)
Set a subsystem string (Subsystem class)
[%number =] %(Subsystem):SetString( name, value, [oldValue])
|%number||A numeric result that indicates whether the string update succeeded. %number is set to 1 upon success. If oldValue is specified and does not match the current setting of the string, the update is not performed and a 0 is returned.|
|%(Subsystem)||The class name in parentheses denotes a shared method. SetString can also be invoked via a Subsystem object variable, which may be null.|
|name||A string that identifies the global string to be set.|
|value||A string that identifies the new value for the global string.|
|oldValue||A string that identifies a value to be compared against the current value of the Subsystem string before doing the update. This is an optional argument.|
- All errors result in request cancellation.
- It is not an error to set a string that is not set.
- SetString sets the string for the current subsystem context, which is indicated by the Context property.
- Unlike SetGlobal, SetString does not turn off multiprocessing, and it is designed for fairly high levels of updating.
- The following statement sets the subsystem string called
- The oldValue argument makes it possible to use Subsystem strings as structures that can be safely updated by multiple users. For example, one might want to maintain a subsystem-wide counter. This can be accomplished as follows:
%value is longString %newValue is float %value = %(subsystem):string('Counter') %newValue = %value + 1 %(subsystem):setString('Counter', %newValue)
Unfortunately, another thread might update the value of the counter between the time the above code retrieves the value (with String) and the time it updates it (with SetString). In such a case, an increment of the counter might be missed. This is more likely, of course, in an MP/204 environment, but you should not count on it being impossible in a non-MP/204 environment. To safely update a counter, you can do the following:
%value is longString %newValue is float %success is float repeat while not %success %value = %(subsystem):string('Counter') %newValue = %value + 1 %success = %(subsystem):setString('Counter', %newValue, %value) end repeat
If no user has updated
Counterbetween the String and the SetString methods, the update would succeed. If some other user has updated it, the update would not be performed, SetString would return a 0, and the repeat loop would be repeated.
While this looks nasty — it seems the code could loop forever — it's not that bad. Since the only thing that causes the SetString to fail is another user updating the same string at the same time; even if a hundred users were in this loop, at least one of them would succeed on each iteration. So unless the subsystem is doing almost nothing else, all the updates would be performed in fairly short order.
- This technique can be used with considerably more complex data-structures. For example, one can actually store a serialized XmlDoc in a subsystem string. A request can retrieve the current structure, manipulate it, and then replace the updated structure:
%value is longString %newValue is longString %myDoc is object xmlDoc %success is float repeat while not %success %value = %(subsystem):string('Complicated') %myDoc = new %myDoc:loadXml(%value) ... manipulate myDoc %newValue = %myDoc:serial(,'EBCDIC') %success = %(subsystem):setString('Complicated', %newValue, %value) end repeat
Note that the above code assumes that the
Complicatedsubsystem string is already set. If the application cannot guarantee that
Complicatedhas been set, there should be a test for the null string, bypassing the loadXml operation and instead populating the XmlDoc with some initial nodes.
The document is stored in the subsystem string in EBCDIC. This is not necessary — the document could be stored in UTF-8 encoding — it is just easier to debug this code if it is saved in EBCDIC.