views:

247

answers:

5

Hello I am writing some data structures in C, and I've realized that their associated functions aren't thread safe. The i am writing code uses only standard C, and I want to achieve some sort of 'synchronization'.

I was thinking to do something like this:

enum sync_e { TRUE, FALSE };
typedef enum sync_e sync;


struct list_s {
//Other stuff
    struct list_node_s *head;
    struct list_node_s *tail;
    enum sync_e locked;
};
typedef struct list_s list;

, to include a "boolean" field in the list structure that indicates the structures state: locked, unlocked.

For example an insertion function will be rewritten this way:

int list_insert_next(list* l, list_node *e, int x){
    while(l->locked == TRUE){
        /* Wait */
    }
    l->locked = TRUE;
    /* Insert element */
    /* -------------- */
    l->locked = FALSE;
    return (0);
}

While operating on the list the 'locked' field will be set to TRUE, not allowing any other alterations. After operation completes the 'locked' field will be again set to 'TRUE'.

Is this approach good ? Do you know other approaches (using only standard C).

+3  A: 

Your code could cause a race condition. You should use a mutex for this.

codaddict
+4  A: 

Standard C doesn't "know" anything about threads. Anything threading related as thread themselves, synchronization primitives, atomic operations are not part of the language or the standard library. They are always part of system libraries as POSIX or the Windows API.

Therefore it is not possible to protect your data structure against a race condition when it is used by multiple threads using only standard C.

If an instance of your structure is only used by a single thread, it can be used in a multi-thread scenario as you e.g. don't use static variables inside your functions.

dmeister
+1  A: 

Unfortunately I don't think Ansi C provides a mutex mechanism... also it doesn't provide a multitheading mechanism as well.

If you want to get a multithreading code which is portable you may chose a primitive set like posix. Of course this is portable on Unix systems only. So, if you want a suggestion, you should program against some high level library with wraps threads and mutexes on different systems. I think that glib should do what you need.

Dacav
+1  A: 

There is no guarantee that

l->locked = TRUE;

will happen instantly within a single atomic operation. It might be compiled into several CPU instructions (that depends on CPU architecture, compiler, operating system etc.)

You should use synchronization mechanisms that are provided by your environment. Those are beyond the scope of the C standard.

Tadeusz A. Kadłubowski
What happens if this thread is interrupted while in the middle of this instruction? The other thread would set `l->locked`, then do it stuff, then reset the lock and return, at which point this thread would start again from where it was.
Gauthier
+1  A: 

The principle is ok, depending on your platform. If you have a very simple processor and the resource is shared between two interrupt routines, this might be enough.

You should be wary of race conditions and priority inversion, look it up.

Gauthier