async task synchronisation

A

anonymous

Hello Experts,

I was wondering about this problem how to solve:

struct async{
int b;
};

async_task(struct async *syn)
{
printf("%s %d\n", __func__, syn->b);
}

main()
{
int i;
struct async *syn = malloc(sizeof(*syn)*10);
for(i=0;i<10;i++) {
syn->b = &i;
async_task(syn) //this function will be called later as it is async
}
//free the memory and do other stuff
}

Problem is async_task is called 10 times rapidly and it is
possible that for loop gets over before async_task function
gets called. So when async_task gets called then it will have
the last value of "syn" i.e. the value gets overwritten as for loop
is executing and async_task function will get last value.

so printf is printing 9 all the times currently. I want it to print
1, 2,3,..... till 9. Basically i want to call async_func for all the values
i had given in argument.

c purists: i apologize for not giving the full code but i am after the
logic. I just want to see how you synchronize in this case.

Just give me a outline.

Solution: I think i can just make a struct and make "sun" as part
of the struct and pass it as below:

struct data{
struct async *syn1;
int counter;
};

struct async{
int b;
};

async_task(struct data *data)
{
for(i=0;i<data->counter;i++)
printf("%d\n", data->syn.b);
}

main()
{
int i;
struct data *data = malloc(sizeof(*data));
data->syn1 = malloc(sizeof(*syn)*10);
struct async *syn=malloc(sizeof(*syn));

for(i=0;i<10;i++) {
syn->b= &i;
data->syn = syn;
data.counter++;
}
async_task(data) ;
}

Is there any better way. Code above is not even compiled
as i am after the logic.
 
K

Kaz Kylheku

Hello Experts,

I was wondering about this problem how to solve:

struct async{
int b;
};

async_task(struct async *syn)
{
printf("%s %d\n", __func__, syn->b);
}

main()
{
int i;
struct async *syn = malloc(sizeof(*syn)*10);
for(i=0;i<10;i++) {
syn->b = &i;

b is of type int. This assignment is a constraint violation
(conversion of integer to pointer without a cast).

Are you sure you don't want:

syn->b = i

If you do put the address of i into every task, then
all the tasks are sharing a pointer to the same counter.
async_task(syn) //this function will be called later as it is async
}
//free the memory and do other stuff

You can't free the memory while async tasks can access it.

What you have here is a storage reclamation problem to solve.

Idea: you could use reference counting. Give each task a back-pointer to a
structure which maintains a refcount and a pointer to the array. The tasks
access this structure through the backpointer, and drop the refcount. When it
hits zero, the array and the reference-count-holding structure are freed.
so printf is printing 9 all the times currently. I want it to print

That probably has to do with some trickery involving you
having taken the address of i, instead of its value.
 
I

Ike Naar

int i;
struct async *syn = malloc(sizeof(*syn)*10);
for(i=0;i<10;i++) {
syn->b = &i;
async_task(syn) //this function will be called later as it is async
}

You allocate an array of 10 struct async elements, but then you call
each async_task with the same element (the first element of the array),
which seems strange.
One would guess that you want to pass each async_task a unique element
from the array, like this:

for (i=0; i<10; i++) {
syn.b = i;
async_task(syn+i);
}

You also need to suspend the deallocation of the array until you
are sure that all async_tasks have terminated.
 
A

anonymous

You allocate an array of 10 struct async elements, but then you call

each async_task with the same element (the first element of the array),

which seems strange.

One would guess that you want to pass each async_task a unique element

from the array, like this:
yes as below, i just wanted to give the idea by giving some piece of code.
for (i=0; i<10; i++) {

syn.b = i;

async_task(syn+i);

}



You also need to suspend the deallocation of the array until you

are sure that all async_tasks have terminated.

right that is already taken care of in my design.
 
J

James Kuyper

Hello Experts,

I was wondering about this problem how to solve:

struct async{
int b;
};

async_task(struct async *syn)
{
printf("%s %d\n", __func__, syn->b);
}

You should declare async_task() as having a return type of 'void', which
has the special meaning (in this context) that the function does not
return a value. C90 permitted you to omit the return type, which would
default to 'int', but it was always a bad idea to make use of that
"feature", which is why it was removed in C99.

Similarly, main() should be declared as returning an 'int', and you
should add 'void' as the argument list, with the special meaning (in
this context) that main() takes no arguments. Leaving out the 'void' is
still permitted as of C2011, but it has never been a good idea to do so;
not since the introduction of function prototypes way back in C90.
{
int i;
struct async *syn = malloc(sizeof(*syn)*10);

You should never call malloc() without checking for the possibility that
it failed.
for(i=0;i<10;i++) {
syn->b = &i;

syn->b is an int object. &i is a value of type "pointer to int". Trying
to assign a pointer value to an int object is a constraint violation.

If syn->b were changed to be a pointer to an int, then the result of
this code is to set syn->b to the same exact value, 10 times. That would
be pointless, setting it the first time would be sufficient.

Therefore, I'm going to assume that the right way to correct this is to
remove the '&'. The rest of my response will be based upon that correction.
async_task(syn) //this function will be called later as it is async

}
//free the memory and do other stuff
}

Problem is async_task is called 10 times rapidly and it is
possible that for loop gets over before async_task function
gets called. ...

Your code, as written above, does nothing that would allow async_task()
to be executed asynchronously; by default, C programs behave as if
statements were evaluated synchronously (and sub-expressions of
expression statements that contain sequence must also be evaluated in an
order that respects those sequence points). C programs don't have to
actually be synchronous - statements that don't interfere with each
order could be evaluated in parallel, on systems where that is possible.
However, whenever it actually matters (as it does in your code), you
must see exactly the same output as you would if the code were executing
synchronously.
... So when async_task gets called then it will have
the last value of "syn" i.e. the value gets overwritten as for loop
is executing and async_task function will get last value.

so printf is printing 9 all the times currently. I want it to print
1, 2,3,..... till 9. Basically i want to call async_func for all the values
i had given in argument.

c purists: i apologize for not giving the full code but i am after the
logic. I just want to see how you synchronize in this case.

The part that's missing from your code is precisely the part that allows
async_task() to be evaluated asynchronously. That's a pretty important
part. Without that part, the answer to your question is trivial: your
code as written already achieves your goal. Yet you describe the
situation as if your code actually mis-behaves in the way that you're
worried about. Therefore, you need to give us at least a simplified
version of the full code; not one that's so simplified that it does not,
in fact, demonstrate the problem you're seeing.

There's several ways to get C code to execute asynchronously; it's
necessary to know which one you're using before anyone can tell you how
to force asynchronous code to synchronize. Prior to C2011, the only way
for C code to run asynchronously that was part of C itself was to use
signal handlers - but it's generally undefined behavior for a signal
handler to call a C standard library function such as printf(), since
they are not guaranteed to be reentrant.

In C2011, features were added that allow the writing of multi-threaded
programs - but if you were using C2011, you should have gotten a
diagnostic message about your failure to provide a return type for
async_task().

You can also make C code run asynchronously by using features defined by
your operating system, rather than by C. However, if that's what you're
doing, in order for anyone to help you with that, you'll have to
identify which operating system it is - the correct solution for one
operating system will be quite different from the one for a different
OS. Once you've done so, the best place to find answers to such
questions is in a forum specific to that operating system. This forum is
not not specific to any operating system.
Just give me a outline.

Solution: I think i can just make a struct and make "sun" as part
of the struct and pass it as below:

struct data{
struct async *syn1;
int counter;
};

struct async{
int b;
};

async_task(struct data *data)
{
for(i=0;i<data->counter;i++)
printf("%d\n", data->syn.b);


There is no data->syn. You also make the same mistake in main(). I'm
going to assume that you meant data->syn1, in both places.
}

main()
{
int i;
struct data *data = malloc(sizeof(*data));
data->syn1 = malloc(sizeof(*syn)*10);
struct async *syn=malloc(sizeof(*syn));

You're doing a lot of dynamic allocation here. It would be simpler to
define data and syn as single objects, and syn1 as a 10 element array.
There may be reasons for using dynamic allocation that would be clear in
your full program, but it's not at all clear from this over-simplified
version. It just looks like a pointless complication.
for(i=0;i<10;i++) {
syn->b= &i;
data->syn = syn;


There is no data->syn. For the rest of my response, I will assume that
it was supposed to be data->syn1.

You have data->syn1 pointing to the exact same syn for all values of
i. I'm beginning to suspect that you don't really understand how C
pointers work.
data.counter++;
}

At this point, syn->b will be 9. Because data->syn1 points at the
same object as syn itself, for all values of i, data->syn1->b will be
9, for all values of i.
async_task(data) ;
}

Is there any better way. Code above is not even compiled
as i am after the logic.

There's still nothing in your program that would allow async_task() to
run asynchronously. Since you've moved it outside of the loop, it now
won't be called until after the entire loop has executed, so it should
print 10 lines, each of which says "9". That's precisely the behavior
you said you wanted to avoid.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top