Is this thread safe?
Jason House
jason.james.house at gmail.com
Sat Jul 12 07:23:15 PDT 2008
I think the following should work. Note the use of a temporary when
rebuilding the table and the two volatile variables.
real logFactorial(uint n) {
static volatile real* factorial_table = ([0.0L]).ptr;
static volatile size_t length = 1;
//Length is guaranteed to never decrease.
//At least at an abstract level, the synchronized part is guaranteed
to //only write to elements >= length.
if(length > n) { // Length can only get larger
return factorial_table[n]; // factorial_table can only get longer
}
synchronized {
if (n >= length){
real* new_factorial_table
if(capacity(factorial_table) < (n + 1) * real.sizeof) {
new factorial_table = cast(real*) realloc(factorial_table,
(n + 1) * real.sizeof);
}
else {
new_factorial_table = factorial_table;
}
for(uint i = length; i<=n; i++) {
new_factorial_table[i] = factorial_table[i-1] + log2(i);
}
factorial_table = new_factorial_table; // safe, length too short
length = n; // safe now that factorial_table is set
}
}
return factorial_table[n];
}
dsimcha wrote:
> From reading over these links, it makes sense to me why my previous
> implementation would not work. However, the articles, which were written
> with C++, not D, in
> mind, recommend using the volatile keyword to solve this. In D, volatile
> is deprecated, even though, according to microbenchmarks I just tried, it
> has much
> less overhead than synchronized. I also understand from reading previous
> forum
> posts that it applies to statements, not variables. If my understanding
> of volatile is correct, my function could be made correct as follows, by
> simply inserting a volatile at the statement that reads factorial_table*.
>
> real logFactorial(uint n) {
> static real* factorial_table = ([0.0L]).ptr;
> static size_t length = 1;
> //Length is guaranteed to never decrease.
> //At least at an abstract level, the synchronized part is guaranteed
> to //only write to elements >= length.
> if(length > n) { //Length can only get larger, cached length is fine.
> volatile real result = factorial_table[n]; //Doesn't use cached
> factorial_table*
> return result;
> }
> synchronized {
> if(capacity(factorial_table) < (n + 1) * real.sizeof) {
> //Is it safe to update the factorial_table pointer like this?
> factorial_table = cast(real*) realloc(factorial_table, (n + 1)
> *
> real.sizeof);
> }
> for(uint i = length; i<=n; i++) {
> factorial_table[i] = factorial_table[i-1] + log2(i);
> }
> //Set new length after all numbers are calculated.
> length = n;
> return factorial_table[n];
> }
> }
>
> Other than the fact that volatile is deprecated, would this be a correct
> fix? If
> so, why is volatile deprecated? If not, is it not correct?
More information about the Digitalmars-d
mailing list