diff -r ae94777fff8f -r 59758314f811 Symbian3/PDK/Source/GUID-93C75E31-6155-48F1-B99C-92ECD0B2C067.dita --- a/Symbian3/PDK/Source/GUID-93C75E31-6155-48F1-B99C-92ECD0B2C067.dita Fri Jun 11 12:39:03 2010 +0100 +++ b/Symbian3/PDK/Source/GUID-93C75E31-6155-48F1-B99C-92ECD0B2C067.dita Fri Jun 11 15:24:34 2010 +0100 @@ -1,120 +1,120 @@ - - - - - -Common -Error Patterns - Execution OrderDescribes a few common error patterns based on thread priority -and multiple active threads in an SMP environment. -

The majority of errors found while testing SMP code are not actually caused -by SMP but are multi-threaded code errors that become more likely to occur -on an SMP system.

-

Many of these errors are caused by the developer making assumptions about -how the scheduler will prioritise some threads, and suspend execution of other -threads while the higher priority thread completes. Even on a single core -system these assumptions can fail if the higher priority thread is not ready -to run or has to wait for a resource, and the scheduler continues execution -of the original thread.

-

Because many of the common error patterns are caused by the same thread -execution assumptions and errors, the solution to many of them is the same: -write good code that doesn't make assumptions but explicitly enforces execution -order or waits until asynchronous events are complete.

-

Examples of common errors that are caused by thread execution order are:

- -
Relying on -linear execution

On a single-processor system, the scheduler usually -grants execution to another thread when the active thread returns from a function -or calls a waiting primitive. This can lead to two kinds of assumptions: assuming -that the other thread will not execute until a later stage, or assuming that -the active thread will block on an asynchronous function call. You must not -rely on either of these, especially on an SMP system.

-
Deleting/re-creating -kernel objects

Kernel objects are objects derived from RHandleBase, -such as threads, semaphores, mutexes. processes and timers. They each have -a name that must be unique within the system and are managed by the supervisor -thread.

If you ask for such a kernel object to be deleted, there may -be a delay before the asynchronous deletion completes. If you try to create -an object with the same name before the kernel has deleted the original object, -the creation will fail. In general it is not possible to determine whether -the kernel has completed the deletion: although there are some APIs that can -be used during development, they are not available for use on a live system.

For -that reason it is important to not reuse names, but to always create kernel -objects with a new unique name for each object. There are APIs available for -many kernel objects to provide new unique names. It is also possible for you -to write your own unique name generator.

-
Passing stack -variables or temporary variables to an asynchronous service -Passing data on the stack - -

When execution leaves a function, the variables that are local to -the function are deallocated from the stack. If you pass local variables as -parameters to an asynchronous function, you must make sure that the other -thread's execution happens before the data is removed from the stack. It is -much better to use objects that persist over the lifetime of an asynchronous -call: for example, a class member variable..

Likewise, deleting an object -after it has been passed to an asynchronous function but before the service -is provided will cause application errors and possibly device panics

-
Making asynchronous -calls that pass a TRequestStatus without calling WaitForRequest() afterwards

On -a single-processor system, calling a waiting primitive always relinquishes -execution control to the scheduler. With adequate thread priorities, the scheduler -may then run the thread in charge of the request. However, this assumption -is not true on an SMP system, where both threads might execute at the same -time.

Therefore, you must use a synchronisation primitive to ensure -that the asynchronous request is complete before continuing on to any code -that relies on the completion of that request.

As for any other asynchronous -request, it is important to wait for the request to complete. Use WaitForRequest() to -ensure that the other thread has finished processing the asynchronous call -before the calling thread can safely progress.

-
Relying on -thread priority for execution order

On an SMP system, you cannot -assume execution order from thread priority. Use semaphores and mutexes to -ensure that the execution order is safe.

-
Relying on -thread priority for publish and subscribe execution order

As the -notification thread and the subscription thread might execute at the same -time, use synchronisation primitives to ensure that your listener is ready -before publishing, and that it is notified before the publication channel -is deleted.

See Common -Error Patterns - Case Studies for an example of a Publish and Subscribe -error pattern.

-
Other race -conditions due to unexpected thread ordering

It is expected that -there may be other race conditions between threads and as these are identified -this document will be updated to describe them.

-
Using non-Symbian -synchronisation APIs

The Symbian synchronisation and IPC primitives -protect data and control thread execution on an SMP system. There is no guarantee -that non-Symbian APIs will give the same protection. For SMP-safe code, only -use the Symbian synchronisation APIs .

See Data -Integrity and Memory Barriers , Atomic -Operations and Locking for -useful synchronisation and atomic operation APIs.

-
-SMP Developer -Tips + + + + + +Common +Error Patterns - Execution OrderDescribes a few common error patterns based on thread priority +and multiple active threads in an SMP environment. +

The majority of errors found while testing SMP code are not actually caused +by SMP but are multi-threaded code errors that become more likely to occur +on an SMP system.

+

Many of these errors are caused by the developer making assumptions about +how the scheduler will prioritise some threads, and suspend execution of other +threads while the higher priority thread completes. Even on a single core +system these assumptions can fail if the higher priority thread is not ready +to run or has to wait for a resource, and the scheduler continues execution +of the original thread.

+

Because many of the common error patterns are caused by the same thread +execution assumptions and errors, the solution to many of them is the same: +write good code that doesn't make assumptions but explicitly enforces execution +order or waits until asynchronous events are complete.

+

Examples of common errors that are caused by thread execution order are:

+
    +
  • Relying +on linear execution

  • +
  • Deleting/re-creating +kernel objects

  • +
  • Passing +stack variables or temporary variables to an asynchronous service

  • +
  • Making +asynchronous calls that pass a TRequestStatus without calling WaitForRequest() +afterwards

  • +
  • Relying +on thread priority for execution order

  • +
  • Relying +on thread priority for publish and subscribe execution order

  • +
  • Other +race conditions due to unexpected thread ordering

  • +
  • Using +non-Symbian synchronisation APIs

  • +
+
Relying on +linear execution

On a single-processor system, the scheduler usually +grants execution to another thread when the active thread returns from a function +or calls a waiting primitive. This can lead to two kinds of assumptions: assuming +that the other thread will not execute until a later stage, or assuming that +the active thread will block on an asynchronous function call. You must not +rely on either of these, especially on an SMP system.

+
Deleting/re-creating +kernel objects

Kernel objects are objects derived from RHandleBase, +such as threads, semaphores, mutexes. processes and timers. They each have +a name that must be unique within the system and are managed by the supervisor +thread.

If you ask for such a kernel object to be deleted, there may +be a delay before the asynchronous deletion completes. If you try to create +an object with the same name before the kernel has deleted the original object, +the creation will fail. In general it is not possible to determine whether +the kernel has completed the deletion: although there are some APIs that can +be used during development, they are not available for use on a live system.

For +that reason it is important to not reuse names, but to always create kernel +objects with a new unique name for each object. There are APIs available for +many kernel objects to provide new unique names. It is also possible for you +to write your own unique name generator.

+
Passing stack +variables or temporary variables to an asynchronous service +Passing data on the stack + +

When execution leaves a function, the variables that are local to +the function are deallocated from the stack. If you pass local variables as +parameters to an asynchronous function, you must make sure that the other +thread's execution happens before the data is removed from the stack. It is +much better to use objects that persist over the lifetime of an asynchronous +call: for example, a class member variable..

Likewise, deleting an object +after it has been passed to an asynchronous function but before the service +is provided will cause application errors and possibly device panics

+
Making asynchronous +calls that pass a TRequestStatus without calling WaitForRequest() afterwards

On +a single-processor system, calling a waiting primitive always relinquishes +execution control to the scheduler. With adequate thread priorities, the scheduler +may then run the thread in charge of the request. However, this assumption +is not true on an SMP system, where both threads might execute at the same +time.

Therefore, you must use a synchronisation primitive to ensure +that the asynchronous request is complete before continuing on to any code +that relies on the completion of that request.

As for any other asynchronous +request, it is important to wait for the request to complete. Use WaitForRequest() to +ensure that the other thread has finished processing the asynchronous call +before the calling thread can safely progress.

+
Relying on +thread priority for execution order

On an SMP system, you cannot +assume execution order from thread priority. Use semaphores and mutexes to +ensure that the execution order is safe.

+
Relying on +thread priority for publish and subscribe execution order

As the +notification thread and the subscription thread might execute at the same +time, use synchronisation primitives to ensure that your listener is ready +before publishing, and that it is notified before the publication channel +is deleted.

See Common +Error Patterns - Case Studies for an example of a Publish and Subscribe +error pattern.

+
Other race +conditions due to unexpected thread ordering

It is expected that +there may be other race conditions between threads and as these are identified +this document will be updated to describe them.

+
Using non-Symbian +synchronisation APIs

The Symbian synchronisation and IPC primitives +protect data and control thread execution on an SMP system. There is no guarantee +that non-Symbian APIs will give the same protection. For SMP-safe code, only +use the Symbian synchronisation APIs .

See Data +Integrity and Memory Barriers , Atomic +Operations and Locking for +useful synchronisation and atomic operation APIs.

+
+SMP Developer +Tips
\ No newline at end of file