I l @ ve RuBoard |
Developing networked applications using the native OS concurrency mechanisms outlined above can cause portability and reliability problems. To illustrate some of these problems, consider a function that uses a UI threads mutex to solve the auto-increment serialization problem we observed with request_count on page 131 in Section 6.4: typedef u_long COUNTER; static COUNTER request_count; // File scope global variable. static mutex_t m; // Protects request count (initialized to zero). // ... virtual int handle_data (ACE_SOCK_Stream *) { while (logging_handler_.log_record () != -1) { // Keep track of number of requests. mutex_lock (&m); // Acquire lock ++request_count; // Count # of requests mutex unlock (&m); // Release lock } mutex_lock (&m); int count = request_count; mutex_unlock (&m); ACE_DEBUG ((LM_DEBUG, "request_count = %d\n", count)); logging_handler_.close (); return 0; } In the code above, m is a variable of type mutex_t , which is automatically initialized to 0. In UI threads, any synchronization variable that's set to zero is initialized implicitly with its default semantics [EKB + 92]. For example, the mutex_t variable m is a static variable that's initialized by default in the unlocked state. The first time the mutex_lock() function is called, it will therefore acquire ownership of the lock. Any other thread that attempts to acquire the lock must wait until the thread owning lock m releases it. Although the code above solves the original synchronization problem, it suffers from the following drawbacks:
In general, native OS concurrency APIs exhibit many of the same types of problems associated with the Socket API in Section 2.3. In addition, concurrency APIs are even less standardized across OS platforms. Even where the APIs are similar, there are often subtle syntactic and semantic variations from one implementation to another. For example, functions in different drafts of the Pthreads standard implemented by different operating system providers have different parameter lists and return different error indicators. Sidebar 13 outlines some of the differences between error propagation strategies for different concurrency APIs. This lack of portability increases the accidental complexity of concurrent networked applications. Therefore, it's important to design higher-level programming abstractions, such as those in ACE, to help developers avoid problems with nonportable and nonuniform APIs.
|
I l @ ve RuBoard |