Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C99: Restricted Pointers to Document Thread Safety?

This question isn't about the technical usage of restricted, more about the subjective usage. Although I might be mistaken as to how restricted technically works, in which case you should feel free to grill me for basing a question on a false premise.

Here are two examples of how I'm using restricted so far:

If I have a function that takes a pointer to a sequence of immutable chars, I don't say it's restricted, since other people are allowed to access the data via their own pointers at the same time as the function's executing, e.g. from another parallel thread. The data isn't being modified, so no problem.

However, if the function takes a pointer to a sequence of mutable chars that it might modify, I say it's restricted because the data absolutely should not be accessed in anyway from any pointer (bar the argument the function uses, obviously) during the execution of the function due to potentially inconsistent data. It also states the possibility of the data being modified, so the coder knows not to read stale data and that they should use a memory barrier when accessing or whatever...

I don't code much C, so I could easily be wrong about what I'm assuming here. Is this correct usage of restrict? Is it worth doing in this scenario?

I'm also assuming that once the restricted pointer is popped off the stack when the function returns, that the data can then freely be accessed via any other pointer again, and that the restriction only lasts as long as the restricted pointer. I know that this relies on the coder following the rules, since accessing a restricted data via an 'unofficial' pointer is UB.

Have I got all of this right?

EDIT:

I'd just like to make clear that I already know it does absolutely nothing to prevent the users from accessing data via multiple threads, and I also know that C89 has no knowledge of what 'threads' even are.

But given that any context where an argument can be modified via reference, it's clear that it mustn't be accessed as the function is running. This doesn't do anything to enforce thread safety, but it does clearly document that you modify the data through your own pointer during the execution of the function at your own risk.

Even if threading is taken completely out of the equation, you still allow for further optimizations in a scenario where it seems correct to me.

Even so, thanks for all your authoritative answers so far. Do I upvote all the answers that I liked, or just the one that I accept? What if more than one is accepted? Sorry, I'm new here, I'll look through the FAQ more thoroughly now...

like image 641
Louis Avatar asked Jul 16 '11 16:07

Louis


2 Answers

restrict has nothing to do with thread safety. In fact, the existing C standards have nothing to say on the topic of threads at all; from the point of view of the spec, there is no such thing as a "thread".

restrict is a way to inform the compiler about aliasing. Pointers often make it hard for the compiler to generate efficient code, because the compiler cannot know at compile time whether two pointers actually refer to the same memory. Toy example:

void foo(int *x, int *y) {
    *x = 5;
    *y = 7;
    printf("%d\n", *x);
}

When the compiler processes this function, it has no idea whether x and y refer to the same memory location. Therefore it does not know whether it will print 5 or 7, and it has to emit code to actually read *x before calling printf.

But if you declare x as int *restrict x, the compiler can prove that this function prints 5, so it can feed a compile-time constant to the printf call.

Many such optimizations become possible with restrict, especially when you are talking about operations on arrays.

But none of this has anything to do with threads. To get multi-treading applications right, you need proper synchronization primitives like mutexes, condition variables, and memory barriers... All of which are specific to your platform, and none of which have anything to do with restrict.

[edit]

To answer your question about using restrict as a form of documentation, I would say "no" to that, also.

You seem to be thinking that you should document when a variable can or cannot be concurrently accessed. But for shared data, the proper discipline is (almost always) to ensure that it is never concurrently accessed.

The relevant documentation for a variable is whether it is shared at all and which mutex protects it. Any code accessing that variable for any reason, even just to read it, needs to hold the mutex. The author should neither know nor care whether some other thread might or might not happen to be accessing the variable concurrently... Because that other thread will be obeying the same discipline, and the mutex guarantees there is no concurrent access.

This discipline is simple, it works, and it scales, which is why it is one of the dominant paradigms for sharing data between threads. (The other is message passing.) If you ever find yourself trying to reason "do I really need to lock the mutex this time?", you are almost certainly doing something wrong. It would be hard to overstate this point.

like image 162
Nemo Avatar answered Sep 21 '22 05:09

Nemo


No, I don't think that this is a good dialect to provide any information about acces from different threads. It is meant as assertions about pointers that a particular peace of code gets for different pointers it handles. Threading is not part of the language, yet. Thread safe acces to data needs much more, restrict is not the right tool. volatile isn't a guarantee, which you sometimes see proposed as well.

  • mutexes or other lock structures
  • memory fences that ensure data integrity
  • atomic operations and types

The upcoming standard C1x is supposed to provide such constructs. C99 isn't.

like image 28
Jens Gustedt Avatar answered Sep 21 '22 05:09

Jens Gustedt