Concurrency control always becomes an issue when dealing with multiple threads of execution. In the thin client three-tier model, multiple clients can update the state of shared objects on the server at the same time. How do you resolve synchronization problems as they occur without coding the concurrency control into the objects themselves? Keep in mind that simple proxy methodologies or RPC mechanisms dont handle concurrency issues automatically. A remote function call that changes an objects state can corrupt or break other clients making similar requests on the same object at the same time.
Lets look at a fairly simple example. Suppose a virtual whiteboard object is running on the server. It contains a list of shapes that have been drawn on the whiteboard by several remote thin clients. The current state of the whiteboard includes a square (item 0), triangle (item 1), and a line of text (item 2). Three clients are currently viewing the whiteboard. Client 1 invokes a command to delete the text (item 2). At the same time client 2 invokes a command to delete the triangle shape (item 1). Also at the same time, client 3 sends a command to add a line. Without concurrency control, the object state will depend on the order in which the commands are handled by the server object.
Heres an example of how optimistic concurrency control resolves this problem (see Figure 8). Lets say the server handles or sees the delete the triangle (item 1) first. The delete command is performed successfully. Next, the server processes the command to delete the text (item 2). Of course, by now the previous delete of the 0th item could corrupt the intent of deleting item 2. The second delete command needs its index to be decreased by one to index 1 (a transformation) to preserve the intent of the command (deleting the text item). Finally, the third command to add a line at the end of the shape list needs no modification since the index of the line item depends on what is currently the last item index. The key to making this scenario work correctly is to use an optimistic algorithm that preserves object states. It is an optimistic approach because no client-to-server negotiation takes place to resolve state change commands. The algorithm assumes that commands can be transformed as they are encountered to preserve the objects integrity. In Figure 8, the immediate action on the whiteboard is translated into the final resolution by the optimistic algorithm.
Figure 8 Optimistic Concurrency Control
The concurrency control example given above is specific to array or list-based data structures. Each data type requires a unique set of rules appropriate to it. Typically, a temporal list is maintained to monitor and adjust operations on data structures based on the data types rules. Commands from the clients can be transformed to preserve the integrity of the transaction. Again, this synchronization capability can exist outside of the regular implementation of application-specific C++ classes if runtime binding and data change callbacks are integral to the object structure or framework.