How is atomic_dec_if_positive atomic? - c

So I am reading atomic.h from Linux source code from here (found it on google. I am not sure if it's legit) and I just can't wrap my mind around this:
how is this atomic?
static inline int atomic_dec_if_positive(atomic_t *v)
{
int c, old, dec;
c = atomic_read(v);
for (;;) {
dec = c - 1;
if (unlikely(dec < 0))
break;
old = atomic_cmpxchg((v), c, dec);
if (likely(old == c))
break;
c = old;
}
return dec;
}

It uses the functions atomic_read() and atomic_cmpxchg(), which surely somewhere will be implemented in assembly language using atomicity features of the microprocessor's instruction set.
It first reads a value and makes sure it is positive, stores the read value in c, the decremented value in dec and calls atomic_cmpxchg() which will atomically do the following: "write dec in *v only if the value in *v is equal to c, and return the old value in *v". That way you make sure that the value in *v was not changed between the two atomic calls. If it fails and the return value was different from the expected contents of *v, it retries the whole process.

The following line
c = atomic_read(v);
means at this point in time we know the value of the atomic_v variable == c. We
decrement c to give us our required value.
dec = c - 1;
Obviously if the number is not positive and 0 is not positive we cannot
decrement it.
if (unlikely(dec < 0))
break;
Now we try and change our known old result with the expected result
old = atomic_cmpxchg((v), c, dec);
This is defined as
int atomic_cmpxchg(atomic_t *v, int old, int new);
If we write it out as follows and assume that the whole function is atomic. We have
int atomic_cmpxchg(atomic_t *v, int old, int new) {
&v->counter = &v->counter == old ? new : old;
return old;
}
Note, I'm treating v as an integer, on x86 it's a struct. At this point we
know that at the point of the the atomic operation happening we get the
old value. Our expected old value is c, so if this is the case then we have
successfully decremented the value, return the result.
if (likely(old == c))
break;
If not we need to reset our expectataion ie our start point, we're decrementing a new value c not the old one we had when last entered the for(;;) loop
c = old;
The important part here is that this is in a loop, this loop will continue until it succeeds to decrement the value or the value is non positive.

Related

Example 1-7 from The C Programming Language(version 2)

I am having trouble understanding the example 1.7 given in The C Programming Language. The main purpose of this example is to illustrate the use of functions in C. The book describes the following program as such, "Since C has no exponentiation operator like ** of Fortran, let us illustrate the mechanics of function definition by writing a function power(m,n) to raise an integer m to a positive power n. That is, the value of power(2,5) is 32. This function is not a practical exponentiation routine since it handles only positive powers of small integers, but it's good enough for illustration."
This is the block of C code that follows:
#include <stdio.h>
int power(int m, int n); /*function prototype */
int main() {
/* test power function */
int i;
for(i = 0; i < 10;++i)
printf("%d %d %d\n",i,power(2,i),power(-3,i));
return 0;
}
/* power: raise base to the nth power;n >=0 */
int power(int base,int n) {
int i , p;
p = 1;
for(i = 1;i <= n;++i)
p = p * base;
return p;
}
I understand everything up to the power function's code block. What is confusing me is that for loop. I am still learning C(obviously, i'm in the first chapter) but I come from JavaScript. So when I see this for loop I expect the i to need to be 'bound' to something for it to be of us in iteration(similar to the first for loop in the example). But the power function returns p after p = p * base;. It's not returning anything to do with i. So to me, I think, what is the purpose of this for loop? I notice that if I comment out the for loop and remove the integer i then the numbers printed out do not increment except for the numbers within the previous for loop. To me, I expect the int n would need to increment. Not the i.
It appears to me that within the for loop that n is only being used as comparison to i. Is the purpose of the for loop in the power function only to execute p = p * base if i <= n is true? That can't be true because if that was then it would better be server with just an if statement and wouldn't need a ++i to increment.
What am I missing here?
The for-loop in the power function repeatedly multiplies (and updates) p by base. It does this n times -- i is the counter. If an if-statement were used, then you'd only get up to one multiplication.

I am not getting desired output for a C program

I am doing a c program but the sample input is not giving the sample output if I use the. I think my program is not calling the function. I guess I have declared it incorrectly. Or my logic is wrong. What I am getting is a zero as output. The question is given below.
Write a C function to find the kth occurrence of an integer n in a sequence of non-negative integers, and then call your function from
main.
Your function should be according to the following declaration:
int find(int n, int k);
Input
You are given the input in two lines:
The first line contains a non-negative integer, say n, and a positive
integer k, in that order. You have to find the kth occurrence of n in
the sequence below.
The second line consists of a sequence of non-negative integers,
terminated with a -1. The -1 is not part of the sequence.
Output
If n occurs k times in the sequence, then output the index of the kth
occurrence of n in the sequence.
If n does not occur k times in the sequence, then output -1.
(For example, the second occurrence of the integer 3 in the sequence
1 1 3 2 3 -1 is at position 4 in the sequence. The first index in the
sequence is 0.)
Input:
3 2
1 1 2 3 3 -1
Output:
4
Code:
#include<stdio.h>
int check(int a,int n ,int k ){
int f;
int value;
int counter=0;
counter++;
if (a==n)
{
f++;
}
if(f==k)
{
value= counter;
}
return value;
}
int main(void)
{
int n , k,a;
int tempo;
scanf("%d",&n);
scanf("%d",&k);
while(a!=-1)
{
scanf("%d",&a);
tempo=check(a,n,k);
}
printf("%d",tempo);
return 0;
}
Your check function has numerous problems:
int check(int a,int n ,int k ){
Your prototype does not match the one in the assignment - you're only supposed to take 2 arguments, neither of which is the sequence of values you're checking against. Somehow, someway, you are supposed to access that sequence from within the body of the function, either by referencing a global array (bad), or by reading the input sequence from within the body of the function (slightly less bad, and probably the intent of the exercise1).
int f;
int value;
auto variables are not implicitly initialized in a declaration - their initial value is indeterminate (it may be 0, it may be a trap representation, it may be a valid non-zero integer value). This will cause problems later.
int counter=0;
counter++;
I think I know what you're trying to go for here, and it won't work as written2 - counter only exists for the lifetime of the function. Each time you call check, a new instance of counter is created and initialized to 0. It won't remember the value stored in it from a previous call.
if (a==n)
{
f++;
f isn't guaranteed to be 0 at this point (or any other specific value). It could be 0, or it could be any non-zero value, or even a trap representation (a bit pattern that does not correspond to a valid integer value).
}
if(f==k)
{
value= counter;
}
return value;
}
At this point, counter is only ever going to be 1 - you initialize it to 0 at function entry and immediately increment it, then you never touch it again. So value is only ever going to be indeterminate or 1.
So, how should you proceed from here and satisfy the requirements of the assignment?
The less bad option is to read the sequence from within the check (or find) function, although that's still pretty bad (again, I/O should be a separate operation, and we're assuming all input comes through stdin).
int find( int n, int k )
{
int next; // next value in the sequence
... // additional items for index, number of matches, etc.
while ( scanf( "%d", &next ) == 1 && next != -1 )
{
// update index, does next match n, is it the k'th match, etc.
}
...
}
scanf is a poor tool for interactive input, but at this point is the simpler approach.
Which, honestly, isn't any better than keeping a global array. I/O should be factored out from computation whenever possible, and if a function *is* required to read from an input stream, that stream should be specified as a parameter to the function - you shouldn't force your code to assume all input comes through stdin.
counter would need to be declared static for it to retain its value from call to call.
My solution is totally extension of what John Bode said above and as John Bode said, you are using more parameters than the preferred. You should stick to only 2 parameters. And as you have two parameters n(for search element) and K(k th occurrence) you cant pass an sequential array to that function, So you should start reading(scanning) the sequence inside the find().
As the program clearly says it terminates with -1. You can use this to end the loop in terminating the find function.
Scan function returns true as long as it reads. even for -1 it returns true so you should use the value!=-1. And inside the loop you can use your logic of matching and finding the index number.
int find(int n, int k){
int next;
int match=0;
int index=0; //for parsing the sequence
while( scanf("%d", &next) ==1 && next!=-1){
if(next == n){
match++;
if(match==k)
return index;
}
index++; //move the index
}
return -1;
}

The difference between n++ and ++n at the end of a while loop? (ANSI C)

this is probably a dumb question but I just can't figure it out. It has to do with the differences between n++ and ++n (which I thought I understood but apparently not).
#include <stdio.h>
#include <math.h>
long algorithmA(int n);
long algorithmB(int n);
int main(){
long A, B;
A = B = 0;
int n = 1;
while(A >= B){
A = algorithmA(n);
B = algorithmB(n);
n++;
}
printf("At n = %d, Algorithm A performs in %ld seconds & "
"Algorithm B performs in %ld seconds.", n, A, B);
}
long algorithmA(int n){
return pow(n,4) * 86400 * 4;
}
long algorithmB(int n){
return pow(3,n);
}
Here you can probably tell I'm trying to see at what point Algorithm A outperforms Algorithm B. The functions and units of time were given to me in a homework problem.
Anyways, I always thought that the order of "++" would not matter at the end of a while loop. But if I put ++n instead of n++, I get the wrong answer. Can somebody explain why?
Edit: Well it WAS showing 24 with ++n and 25 with n++, but it must have been for another reason. Because I just checked now and there is no difference. Thanks for your patience and time guys, I just wish I knew what I did!
If you increment without assignment, no difference. However, in the following circumstances, there is:
int n = 1;
int x = n++; // x will be 1 and n will be 2
In this example, the statement gets executed prior to the increment.
int n = 1;
int x = ++n; // both x and n will be 2
However, in this example, increment occurs prior to the execution of the statement.
Operator precedence can help you out.
The only difference between n++ and ++n is that n++ yields the original value of n, and ++n yields the value of n after it's been incremented. Both have the side effect of modifying the value of n by incrementing it.
If the result is discarded, as it is in your code, there is no effective difference.
If your program is behaving differently depending on whether you write
n++;
or
++n;
it must be for some other reason.
In fact, when I compile and execute your program on my system, I get exactly the same output in both cases. Adding newlines to the output format, I get:
At n = 25, Algorithm A performs in 114661785600 seconds &
Algorithm B performs in 282429536481 seconds.
You haven't told us what output you're getting. Please update your question to show the output in both cases.
The prefix versions (++n) alter the variable and then pass along its value.
The postfix version (n++) pass along the current value and then alter the variable.

Recursive function to loop and stack

It's well known all recursive functions can be written using just a single loop and a stack. Although this conversion can be criticized to be ugly or less readable, its main use is obviously to avoid smashing the heap.
There are natural ways to convert simple recursive functions into loops. For instance, take the simple tail-recursion elimination using an accumulator. So far, I have not seen yet a definitive answer for this question.
At least to me, sometimes it seems black magic to convert such recursive functions into loops provided a stack. For instance, think of writing a non-recursive version for
f(n) = n, if n <= 1
f(n) = f(n-1) + f(n-2) + 1, if n > 1
The very point underlying this question is:
Is there a lucid, general method to convert a recursive function into a loop + stack?
Feasibility (100%):
From here, we know that any recursive function can be converted to iterate (into a loop) but you need to use a stack yourself to keep the state.
How to do this (generally):
You can check out the article How to replace recursive functions using stack and while-loop to avoid the stack-overflow, which gives examples and steps (10 steps/rules) on how to convert recursive functions to stack and while-loop. See the following part for real example.
Example:
Take the following recursive function as an example:
// Recursive Function "First rule" example
int SomeFunc(int n, int &retIdx)
{
...
if(n>0)
{
int test = SomeFunc(n-1, retIdx);
test--;
...
return test;
}
...
return 0;
}
After applying the 10 rules/steps introduced in the article (details shown in comments), you will get:
// Conversion to Iterative Function
int SomeFuncLoop(int n, int &retIdx)
{
// (First rule)
struct SnapShotStruct {
int n; // - parameter input
int test; // - local variable that will be used
// after returning from the function call
// - retIdx can be ignored since it is a reference.
int stage; // - Since there is process needed to be done
// after recursive call. (Sixth rule)
};
// (Second rule)
int retVal = 0; // initialize with default returning value
// (Third rule)
stack<SnapShotStruct> snapshotStack;
// (Fourth rule)
SnapShotStruct currentSnapshot;
currentSnapshot.n= n; // set the value as parameter value
currentSnapshot.test=0; // set the value as default value
currentSnapshot.stage=0; // set the value as initial stage
snapshotStack.push(currentSnapshot);
// (Fifth rule)
while(!snapshotStack.empty())
{
currentSnapshot=snapshotStack.top();
snapshotStack.pop();
// (Sixth rule)
switch( currentSnapshot.stage)
{
case 0:
// (Seventh rule)
if( currentSnapshot.n>0 )
{
// (Tenth rule)
currentSnapshot.stage = 1; // - current snapshot need to process after
// returning from the recursive call
snapshotStack.push(currentSnapshot); // - this MUST pushed into stack before
// new snapshot!
// Create a new snapshot for calling itself
SnapShotStruct newSnapshot;
newSnapshot.n= currentSnapshot.n-1; // - give parameter as parameter given
// when calling itself
// ( SomeFunc(n-1, retIdx) )
newSnapshot.test=0; // - set the value as initial value
newSnapshot.stage=0; // - since it will start from the
// beginning of the function,
// give the initial stage
snapshotStack.push(newSnapshot);
continue;
}
...
// (Eighth rule)
retVal = 0 ;
// (Ninth rule)
continue;
break;
case 1:
// (Seventh rule)
currentSnapshot.test = retVal;
currentSnapshot.test--;
...
// (Eighth rule)
retVal = currentSnapshot.test;
// (Ninth rule)
continue;
break;
}
}
// (Second rule)
return retVal;
}
BTW, the above article is the Prize winner in Competition <Best C++ article of July 2012> of CodeProject, so it should be trust-able. :)
Yes, but the solution won't be much better than the recursive one except maybe reduce the chance for a stack overflow.
By looking at the sequence, which is similar to the Fibonacci sequence except you add 1 to the result for every round except n = (0,1), you see a pattern.
0 1 2 4 7 12 20
\ \___ ...\____
0+1+1 1+2+1 7+12+1
Since the whole generation is dependent on the two previous numbers you can have two variables in a loop representing that and you don't need to have a stack at all.
//intentional generic algol dialect
int modfib (int n)
{
if( n <= 1 )
return n;
n = n - 2;
int a=2;
int b=4;
int tmp;
while( n-- > 0 )
{
tmp=a;
a=b;
b = tmp + b +1;
}
return a;
}
Until compilers know to do this we still need humans to optimize code.

Variable being used without being initialized? C Language

I can't quite figure out what my issue is here. I keep getting an error in my code.
Error: Run-Time Check Failure: Variable used without being initialized.
: warning C4700: uninitialized local variable 'b' used
can someone help me solve this problem ? Any help would be appreciated.I'm using visual studio as a compiler for C and I'm a beginner in it and this is a one of the assignment. I don't see why i keep getting this issue if i input "int b;" in the beginning of the program. Wouldn't that variable be initialized?
Here is the code:
#include <stdio.h>
//Create a program that asks the user to enter a number until the user enters a -1 to stop
int main()
{
int b;
//as long as the number is not -1, print the number on the screen
while(b!=-1) {
printf("Hello there! would you please enter a number?");
scanf(" %d",&b);
//as long as the number is not -1, print the number on the screen
if(b!=-1){
printf("Thank you for your time and consideration but the following %d you entered wasn't quite what we expected. Can you please enter another?\n",b);
//When the user enters a -1 print the message “Have a Nice Day :)” and end the program
}else {
printf("Have a Nice Day :), and see you soon\n");
}
}
return 0;
}
When you declare a variable, such as you have:
int b;
It is not initialised to have any value, it's value is unknown until you initialise it.
To fix this error, replace
int b;
With
int b = 0;
Error is here:
int main()
{
int b;
//as long as the number is not -1, print the number on the screen
while(b!=-1) {
Since you haven't initialized b, it can be anything. You then use it as a condition for while loop. This is very dangerous.
It may be that system randomly assign value of -1 ( its a rare possibility ) to it .. in that case your while loop will not be actioned
Intialize b to some value
For eg do this:
int b = 0;
You're doing:
int b;
and then doing:
while(b!=-1) {
without ever initializing b. The problem is exactly what your warning is telling you it is.
C does not automatically initialize local variables for you, the programmer has to take care of that. int b allocates memory for your variable, but doesn't put a value in there, and it will contain whatever garbage value was in that memory prior to allocation. Your variable won't be initialized until you explicit assign, or another function explicitly assigns, a value to it.
int b;
is a variable declaration. Explicitly, the value is not initialized. The compiler will emit instructions for the program to reserve space to store an integer at a later time.
int b = 1;
this is a variable declaration with initialization.
int b;
while (b != -1)
this is use of an uninitialized variable, but so is
int a = rand() % 3; // so 'a' can be 0, 1 and or 2.
int b;
if (a == 0)
b = 1;
else if (a == 1)
b = 2;
printf("b = %d\n", b);
this is also a potential cause of uninitialized use of b. If 'a' is 2, we never assign a default value to b.
Upshot is you should always try to specify the default value with the declaration. If the logic that will determine initialization is complex, consider using an out-of-bounds value, as you are using -1.
Can you spot the bug in the following?
int b = -1;
if (a == 0)
b = 1;
else if (a == 1)
b = 2;
else if (a > 2)
b = 3;
if (b == -1) {
// this is an error, handle it.
}

Resources