Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write into an array from a dispatch_apply (GCD) loop?

I have written code to calculate the dynamics of a large set of coupled master equation using the Runge-Kutta-method. The code contains a lot of for-loops, where each step is independent. I intend to use Grand Central Dispatch to speed up the program. I based my attempt on an example I found at http://www.macresearch.org/cocoa-scientists-xxxi-all-aboard-grand-central . Neither my code nor the example on macresearch compile on my machine (MacOSX 10.6.8 Xcode 4.0.2). So here is my code:

...
    double values[SpaceSize], k1[SpaceSize];    

        for ( int t=1 ; t<Time ; t++ ) {

            dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

            //k1
            for (int k=0 ; k<SpaceSize ; k++ ) values[k]=Concentration[k][t-1];

            dispatch_apply(SpaceSize, queue,
                       ^(size_t k)  {
                           k1[k]=h * derives(values, SpaceSize, k); //<--error      
                                    }
                        );
...

It breaks with the error:

Semantic Issue: Cannot refer to declaration with a variably modified type inside block

I tried replacing the arrays (values, k1) with a vectors, but then I get another error message instead:

Semantic Issue: Read-only variable is not assignable

That is where I'm stuck, not really knowing what those error messages are trying to tell me. I spend quite some time searching and asking around if anyone could help. I would be very grateful for tips or better ways to solve this.

like image 974
Jofro Avatar asked Jul 06 '11 21:07

Jofro


2 Answers

error: cannot refer to declaration with an array type inside block

Under the blocks implementation, it is not allowed to access to an C array from blocks. (I can't find the documentation about it...)

There is an easy fix :-)

double valuesArray[SpaceSize], k1Array[SpaceSize];    
double *values = valuesArray, *k1 = k1Array;
like image 147
Kazuki Sakamoto Avatar answered Nov 18 '22 05:11

Kazuki Sakamoto


To store into a captured variable, you need to add the __block storage specifier to its declaration. That should fix the std::vector problem you're seeing.

The issue with a variably-modified type makes it sound like you're using a variable-length array. These can't be referred to from within blocks, because they can't reliably be copied into the block's context (basically a custom C struct type), and they can mess up offsetof-style calculations when working with the context. You can solve this problem by working with a fixed-size variable (just use the maximum size you'll need), moving the arrays into global/static storage, or allocating a pointer and doing the pointer arithmetic to access the second dimension yourself.

like image 29
Jeremy W. Sherman Avatar answered Nov 18 '22 04:11

Jeremy W. Sherman