Languages

Menu
Sites
Language
GCD. Illusion of presence.

Greetings!

Reading the documentation, I've found out a statement: the developers are able to use Apple's GCD within the apps on Tizen platform (Tizen 2.0 Release Notes). Quite a thrilling announcement, isn't it? Unfortunately, in fact the things are not the way they seem to be. Yes, it is true the LLVM compiler gets its job done; nevertheless almost all "killer"-features of GCD are not applicable e.g. none of the blocks dispatched on the main queue are performed. So the dispatch_asynch in company with the background queues of default priorities become useless due to there is no way to return to the main queue from the background ones (just for information, to be able to return to the main queue the dispatch_main() needs calling; that is never done due to the apps on Tizen platform has their own run loop). Another thing that isn't clear is the memory management: what is the right way to manage the objects allocated on the heap and passed in the blocks? Is it the same way the objects are treated within the appications on Objective-C?

As the result, the Tizen-team seems to me too quick to claim such statements. IMHO, deceiveing the developers is not the best way to attract their attention. Dear Tizen-team, I guess I'm not alone who's looking forward to your feedback. Or, at least, update the documentation to avoid misunderstanding.

Regards!

Edited by: Brock Boland on 17 Mar, 2014 Reason: Paragraph tags added automatically from tizen_format_fix module.

Responses

15 Replies
MooChang Kim

Hi.

if you don't mind, could you provides code example that doesn't work with it's expected result?

and which statement will be good to don't make misunderstanding?

Regards

MooChang.Kim

 

Maxim Zabelin

Hello!

To reproduce the desribed issue, please create a new project (I suggest using one of the pre-defined templates e.g. the frame-based application). Next, to enable GCD usage, please follow the steps below:

  1. In the Project Explorer, right-click on the project and select Properties.
  2. In the Properties window, select C/C++ Build > Settings.
  3. On the Tool Settings tab:
    1. Select C++ Compiler > Miscellaneous.
    2. Add the -fblocks compiler option in the Other flags field and click OK.

      The -fblocks option enables LLVM to process the Blocks feature, such as a "^" keyword.

  4. To use other GCD features, include the dispatch/dispatch.h header file in the application. On the Tool Settings tab:
    1. Select C++ Linker > Libraries.
    2. Add the dispatchBlocksRuntime, and kqueue libraries to the Libraries field and click OK.

Next open the <YourAppName>Frame.cpp file, find OnInitializing()'s implementation and put the following code lines in there:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            AppLog("[ Trace ]");
        });
    });

*make sure the stdio.h and dispatch/dispatch.h are included.

The last step to take is to asseble and run the newly created application. Once it's done, you would expect to see [ Trace ] in the console. Unfortunately, you will never see this output; that is the described issue.

Regards,

Maxim

 

p.s. Sorry for the delay, I had a lot of job to get done.

MooChang Kim

Dear Maxim.

thanks for the valuable information.

I'll check it and get back to you soon.

Regards

MooChang.Kim

 

MooChang Kim

Dear Maxim.

with your code example, now I got the point of the main queue issue.

this needs to be resolved or needs to be mentioned as a limitation in document.

to resolve this issue...  I think we can apply below link's approach..

http://nickhutchinson.me/libdispatch/

what do you think?

Regards

MooChang.Kim

 

Maxim Zabelin

Dear MooChang,

 

I've reviewed the suggested approach and it seem to me applicable (as long as it guarantees thread-thefety and keeps the developers away from manual thread synchronization). Nevertheless there is a point make me curious: IIRC, the developers will have to choose between GCD and native Tizen threading, won't they? Asking this question I do not mean the main thread of an application - I mean the case when the application already uses a set of subsidiary threads e.g instances of the Tizen::Base::Runtime::EventDrivenThread class.

 

Considering mention of the limitations, I think it would be highly appreciated by other developers; to me it does make sense (even on temporary basis till the issue stays alive).

 

Meanwhile I'd like to ask one more question: Could you please provide more details about memory management? To me it's still not that clear. Thank you in advance!

 

Best regards,

Maxim.

MooChang Kim

Dear Maxim.

currently Tizen native app developer have three choices that using native Tizen threading, libdispatch(GCD) or libgomp(OpenMP) to utilize multicore.

 

because Tizen 2.2.1 was released and freezed just a few weeks ago... it will take time to update public document... I'm afraid fixing may faster then doc udpate..  :(

 

and regarding memory management... I thought it is controlled by libdispatch and libBlocksruntime.. and didn't get a chance to dig..

I ran valgrind with test code using blocks.. but nothing special..

I don't want to bothering you but could you narrow it down more?

 

Thanks & Best regards,

MooChang.Kim

Maxim Zabelin

Dear MooChang,

Please take my apologies for delay: I still have a set of urgent tasks... Anyway, please, do not hesitate to contact me; I'll do my best to answer you ASAP.

Considering difficulty in documentation update, to tell the truth, it's frustruating to me; nevertheless let's hope this thread could provide assistance to the interested ones.

Now let me turn to my question about memory management: You're definitely right I'd better be more exact in wording.

First I'd like to correct a mistake of mine: talking about memory management, I didn't really mean GCD - I meant blocks. In fact I'm interested in what happens to the objects passed in blocks and the blocks which execution I'd like to postpone for a while. One may say that this point is pretty well described by Apple; that is true, except that Apple talks about this in context of Objective-C, ARC and LLVM. For example, Blocks Programming Topics by Apple says (QFT): "Although blocks are available to pure C and C++, a block is also always an Objective-C object." That makes me wonder: what is a block in Tizen? I doubt a Tizen's block is an Objective-C object. So I'm interested in how a block is preserved till it is displatched on a queue? Imagine a C++ class having a block as a private member; how do I assing this member from inside and outside of an instance of the class? May I simply use an assignment operator (object.block = ^(void){/*do nothing*/})? What is a (the?) correct way to define a setter on the class to assign this private member from outside?

Considering the case when a C++ object is passed to the block, I've already performed an investigation and come up with the following results:

  1. If a C++ class has no copy constructor, one is unable to pass any object of this class in a block by value. That was the easiest one due to a remark of Apple (for details see C++ Objects).
  2. Passing any C++ object by pointer in a block, one has to take care of the life-cycle of this object; that may appear to be a quite difficult task to perform. I'd say boost could handle this for me; in fact it doesn't cover all the cases. If I were asked why I'd say because of the controls and containers Tizen SDK provides: life cycle of a control or container that is bound to the control tree of an app is managed by this tree. So, how do I managed to know if a control is still alive from within a block?

In fact, there are some more points that are not clear to me; though I'm not ready to ask about them right away (I'd like to perform a couple of test first). I also guess I've already asked enough question at once.

Thank you for your patience!

Regards,

Maxim

 

p.s. I guess I'm too bound to the context of Objective-C and advanced Apple features; that's why it's difficult to me to get these particular points in the context of C++. I hightly appreciate any help.

MooChang Kim

Dear Maxim.

it's very nice to have a chance to talk about using libdispatch(GCD) in tizen with you.. I think this is the first thread since libdispatch was ported to tizen.. before this thread, there was no feekback at all..

on the other hand, I'm afraid my knowledge is not enough to discuss about that very detail technical issue.. because myself is not heavy user of libdispatch and Objective-C including blocks.

but I can tell you that once specific issue is decided, then I'll dig into it and do my best to get answer.

 

regarding using blocks as class number. my test code is like belows and it works

class myClass{

   void setter(void (^ccc)(size_t));

private:

    void (^bbb)(size_t);

}

void (^aaa)(size_t)=^(size_t a)

{

    AppLog("test");

}

void

MyClass::setter(void (^ccc)(size_t))

{

   bbb = ccc;

}

// in any member api of myClass

{

       setter(aaa);

      dispatch_apply(10, queue, bbb);

}

 

I'll keep trying to update documents with 'main queue limitation' and let you know once it is done.

Regards

MooChang.Kim

Maxim Zabelin

Dear MooChang,

I've reviewed your example: According to Apple's documentation, your source code must crash (unless the aaa is global), while it never crashes (even if aaa is defined locally (please see my example below)). For details please refer to Copying Blocks; it declares that any block is a stack-allocated object and one must push it onto the heap in case the block needs executing after destruction of the scope within which it was declared.

class GCD

{

    typedef int (^Accumulator)(int, int);

 

    void

    Method1(void); // this one is always called before the Method2 (see below)

    void

    Method2(void);

 

    Accumulator accumulator_;

};

void

GCD::Method1(void)

{

    accumulator_ = ^(int a, int b){

        return (a + b);

    };

    // Instead of the code lines written above, in Objective-C, I would write the following: accumulator_ = Block_copy(^(int a, int b){return (a+b);};)

    // Unfortunately, compiler claims Block_copy is undefined... FYI, Block_copy had been used before ARC came up.

}

 

void

GCD::Method2(void)

{

   // The flow must crash on the next line.

   AppLogDebug("[ 1 + 1 = %i ]", accumulator_(1, 1));

   // Unexpectedly, it reaches this point...

}

 

So I wonder why the things are the way they are. Hope my example and clues might become usefull.

 

Best regards,

Maxim.

MooChang Kim

Dear Maxim.

this is interesting issue to me..  :) in point that we needs to find out why it is NOT crashing.. :)

in my observation with gdb, 'accumulator_' is a structure(I guess it is meta data of block??) pointer and one of it's member is a function pointer. (in your example, it will be 'return a+b')

and that function pointer value is code area address of executable..

so your example code didn't crash because code exist not in the stack.. and structure fields are copied in the Method1.

it may requires more complex blocks to generate crash.. but I don't know how to create it now... I'll check more about this..

 

and below is how to use Block_copy API.

extern "C" void *_Block_copy(const void *aBlock);

{

      accumulator_ = (Accumulator)_Block_copy(^(int a, int b){return(a+b);});

}

Best regards.

MooChang.Kim

Maxim Zabelin

Dear MooChang,

 

Thank you for the explanation! I'll try your suggestions ASAP.

Meanwhile, I'd like to share my experience in testing blocks in C++ & Tizen: there is no way to check whether a block points to nil or not. In other words, neither (block_variable == null) nor (block_variable == 0) returns true. Both of them always return false. I wonder is there any way to know whether a block variable is ever assigned or not. What whould you say?

 

Regards,

Maxim.

MooChang Kim

Dear Maxim.

thanks for the valuable feedback always. :)

I checked block assign issue..

when I see block variable in the gdb, it is a pointer of structure..it seems this structure contains meta data of block.

and because of this, declare block variable does not initialize it's contents and it has garbage value at first.. that's why comparing block variable with null returns false.

but manual initializing with null was possible.. like initialzing other primitive variables.

after manual initializing.. it was possible to check if it is null or assigned block as well.

==========================

GCD gcd;

if(gcd.accumulator_ == NULL)

    AppLog("this will not be printed");

gcd.accumulator_ = NULL;

if(gcd.accumulator == NULL)

    AppLog("this will be printed");

==========================

if we change block to class instead of structure.. then this issue may become clear.. but I'm afraid that will break block's compatibility with C language...

any comments or new issues are welcome.

have a nice weekend!

Thank you.

MooChang.Kim

Maxim Zabelin

Dear MooChang,

You're totally right: it's C++ and it is me who is in charge of initialisation of class members (as well as local variables) with default values. I guess I'm a bit "iOS & Objective-C spoilt" (that does me a favor and always assigns nil as the default value). Shame on me... Thank you for the explanation!

Up to convertion from struct to class, - I completely agree with you: it isn't worth the price.

BTW, I've decided to read clang's documentaion; I think it should clear some points to me. If I get anything that might be interesting I'll let you know. Please also feel free to contact me. 

Considering the weekend, - thank you! I wish you the same!

Regards,

Maxim.

MooChang Kim

Dear Maxim.

now Tizen document is updated to add main queue issue and objective-c / C++ diff issue as a limitation.

https://developer.tizen.org/dev-guide/2.2.1/org.tizen.native.appprogramming/html/guide/libraries/gcd.htm

hope this document and this thread helps who are using gcd in Tizen.

Thank you again :) and from now on, I'll focus to resolve main queue issue ASAP.

Regards

MooChang.Kim

 

Maxim Zabelin

Dear MooChang,

 

Please take my apologies for such a long response delay: the end of the year (as well as its beginning) was full of releases and deadlines. Now I've finally get a piece of free time to thank you: me and my teammates do appreciate you help, thank you!

BTW, how is the main queue issue going?

 

Regards,

Maxim.