From RTSC-Pedia

Jump to: navigation, search
revision tip
—— LANDSCAPE orientation
[printable version]  offline version generated on 04-Aug-2010 21:08 UTC

Using xdc.runtime Gates/Example 1

Adding concurrency support for pthread-based applications

Contents

Using Gate in a pthread-based Application

Before showing the use of Gate, we start with a somewhat contrived multi-threaded application that has a concurrency bug. Then we look at how the Gate module is used to fix the application.

A Simple Multi-Threaded Application

In the somewhat contrived example below we show a pthread-based application that creates two threads that each increments a global counter, named count, by one N times. When the application completes, we expect that the counter's value is precisely 2 * N. However, unless special precautions are taken, the final value of the counter may differ from 2 * N. How is this possible? Incrementing a global variable often requires several instructions (to read the current value into a register, increment the register, and write the new value to memory) and threads can preempt one another between any two instructions. So, starting with count = 0, the following sequence of instructions is possible:

  1. thread 0 reads count (= 0) into register A
  2. thread 1 reads count (= 0) into register A
  3. thread 0 increments and stores A (= 1) to count
  4. thread 1 increments and stores A (= 1, because each thread has a "private" version of A) to count

If this sequence is repeated for the entire run of the application, the final value of count will be N rather than 2 * N.

app.c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#include <stdio.h>
#include <pthread.h>
 
#define N   1000000
#define T   2
 
Int count = 0;   /* global counter updated by all threads */
 
/* ======== thread ======== */
static Void thread(Void *state) {
    Int i;
    printf("starting thread %d\n", *(Int *)state);
    for (i = 0; i < N; i++) {
        count++;                        /* update global data */
    }
    printf("thread %d done.\n", *(Int *)state);
}
 
/* ======== main ======== */
Int main(Int argc, String argv[]) {
    pthread_attr_t pattrs;
    pthread_t      pthread[T];
    Int            i, state[T];
 
    pthread_attr_init(&pattrs);
    for (i = 0; i < T; i++) {            /* create T threads */
        state[i] = i;
        pthread_create(&pthread[i], &pattrs,
            (void *(*)(void *))thread, (void *)(state + i));
    }
 
    for (i = 0; i < T; i++) {
        pthread_join(pthread[i], NULL);  /* wait for them to complete */
    }
 
    if (count != (N * T)) {              /* check their work */
        fprintf(stderr, "count = %d, should be %d\n", count, N);
        return (1);
    }
    return (0);
}
Output
 
 
 
 
 
starting thread 0
starting thread 1
thread 0 done.
thread 1 done.
count = 162752, should be 200000

How to Use Gate to Protect Global Data

Gates are used to protect modifiable data structures that are shared between two or more threads in a multi-threaded environment. In the application above we saw that when multiple threads update shared data, if these threads can preempt on another at arbitrary points in the instruction stream, there is a risk that the data will not be consistently updated. Gates provide a way to control or serialize access to global data and prevent the anomalies seen above.

To prevent this anomaly, we can modify the implementation of the thread() function above to encapsulate the modification of count with calls to Gate_enterSystem() > and Gate_leaveSystem() <. Since only one thread can be "in the system gate" at a time, the entire sequence of instructions that updates count is guarenteed to be executed without interruption. As a result, all threads will store a properly updated count before another thread can read it and the final value of count in the new application should always be 2 * N.

C Code
 
 
 
 
 
 
>
 
<
 
 
 
#include <xdc/runtime/Gate.h>
 
static Void thread(Void *state) {
    Int i;
    printf("starting thread %d\n", *(Int *)state);
    for (i = 0; i < N; i++) {
        IArg key = Gate_enterSystem();  /* enter critical section */
        count++;                        /* update global data     */
        Gate_leaveSystem(key);          /* leave critical section */
    }
    printf("thread %d done.\n", *(Int *)state);
}

Since we added a reference to a RTSC module, Gate, we need to add a configuration script that declares that we are using this module, run the RTSC configuration tool, and link the application above with the output. But if we re-run the application, the gate does not seem to help.

Config Code (Wrong!)
 
xdc.useModule("xdc.runtime.Gate");
Output
 
 
 
 
 
   starting thread 0
   starting thread 1
   thread 0 done.
   thread 1 done.
   count = 126370, should be 200000

The problem is twofold: although we need to use the Gate module, as shown above, we also need to

  • create an instance of a "real" gate, and
  • "bind" this instance to the System module's common$.gate configuration parameter

The Gate_enterSystem() method uses a the gate instance associated with the System module. Unless we bind a non-trivial gate instance System, Gate_enterSystem() will operate on a default gate instance created from GateNull. If we assume there is a module named examples.runtime.gates.Lock that provides a posix-based implementation of IGateProvider, we can finally fix the application with the configuration script shown below.

Config Code (Right)
 
 
 
 
 
var Gate= xdc.useModule("xdc.runtime.Gate");
 
var System = xdc.useModule("xdc.runtime.System");
var Lock = xdc.useModule("examples.runtime.gates.Lock");
System.common$.gate = Lock.create();
Output
 
 
 
 
starting thread 0
starting thread 1
thread 0 done.
thread 1 done.

A complete implementation of this presumed examples.runtime.gates.Lock module appears in the Runtime Gate Provider Example 1.

See also

Extending xdc.runtime Gates/Example 1 A posix-based IGateProvider implementation

[printable version]  offline version generated on 04-Aug-2010 21:08 UTC
Copyright © 2008 The Eclipse Foundation. All Rights Reserved
Views
Personal tools
package reference