Wednesday, April 29, 2009

Memory Barriers in multi-threaded applications

Sometimes, the compiler can get in the way and break your code because it makes single-thread assumptions about your code. In addition, the microprocessors can break your code because it makes single-core assumptions. The way to fix this is use a memory barrier.

Here is a very good description of the problem of multi-threading.


Here is how to do it on a PowerPC, using the lwsync instruction.

volatile unsigned variable1 = 0;

#define barrier() __asm__ volatile (”lwsync”)

#define ITERATIONS 50000000

void *writer(volatile unsigned *variable2) {
utilBindThreadToCPU(0);
for (;;) {
variable1 = variable1 + 1;
barrier();
*variable2 = *variable2 + 1;
}
return NULL;
}

How to predeclare typedefs for self-referential typedefs

Sometimes you need to have a typedef that refers to itself through a struct member, or there is a circular reference. Here is how to predeclare the typedef so you can use it before it is fully defined. It's basically 3 parts. First declare the struct, then declare the typedef, then define the struct using the typedef.


struct fileinfo;
struct cached_block;

typedef struct fileinfo FILEINFO;
typedef struct cached_block CACHED_BLOCK;

struct fileinfo {
FILEINFO *fi_next; /* list of all files */
CACHED_BLOCK *fi_blks; /* cached blocks for this file */
/* ... */
};

struct cached_block {
int cb_lbn; /* logical block number */
CACHED_BLOCK *cb_next; /* next cached block for this file */
FILEINFO *cb_file; /* file containing this block */
/* ... */
};