LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

alignment of doubles cvi native compiler

Does anyone know if the native CVI compiler always properly aligns doubles?  I.e., if I declare a double will the memory location always be on an 8 byte boundary?

 

The Intel architecture docs say that if they are, reads and writes of double can be considered atomic.

 

Thanks.

0 Kudos
Message 1 of 10
(4,646 Views)

menchar:

 

I'm not sure if this answers your question, but in CVI 9.0.1, it is possible to force a double off of an 8 byte boundary using some pointer manipulation.  I haven't caught one off an 8 byte boundary as natively assigned.

 

The attached project assigns a bunch of different variable types, some doubles interspersed with other types, and checks the addresses and byte boundaries of the variables.  Then it forces a double off of an 8 byte boundary by forcing its pointer into the middle of a string.

 

Why does it matter?

0 Kudos
Message 2 of 10
(4,614 Views)

An atomic operation cannot be interrupted. This has advantages for example in those cases where multiple threads can access the same variable - you will never catch an atomic variable with one half of it set to a value by one thread and the other half set by a different one. There is a fuller description in Wikipedia.

 

JR

0 Kudos
Message 3 of 10
(4,603 Views)

exactly jr.

 

I have a multi threaded application with a measurement thread that stores measurements as doubles in a common area where they can be read and used by other threads.  If I know the doubles writes/reads are atomic, then there's no chance that a consumer thread will see a partial value and I don't have to go through the hassle of protecting the variable when it's accessed.

 

I didn't doubt that you could force a double off of 8 byte alignment if you wanted to, I was mostly curious if anyone could vouch for the compiler when doing simple double declarations.

 

Thanks to everyone.

 

Menchar

0 Kudos
Message 4 of 10
(4,581 Views)

I've used this trick pretty much form day one with integers that match the word length of the system but have never been bold enough to try it on doubles as some compliers may used enhanced 10-byte doubles.

 

I suspect it should work with doubles on a 64-bit machine with 64-bit OS but I doubt any benefits over using proper critical section locks would be noticeable on a modern multi-core CPU.

 

Aligning structures across different compilers has always been an issue the #pragma pack(n) can be the solution if it actually works for your set of compilers.  I usually go old school when designing cross-platform structures and manually add "spare" or "reserved" entries to make sure things align.

 

0 Kudos
Message 5 of 10
(4,568 Views)

I spoke a couple years ago to one of the original Intel x86 architecture designers and it was always Intel's intent that aligned double ops be atomic.

 

Writing critical sections / mutexes is a hassle, I don't do it for integer ops and I won't for doubles either.

 

I don't have to worry about multiple platforms or compilers.

 

But I can see where if you were concerned about maximum portability you might want to use protection.

 

0 Kudos
Message 6 of 10
(4,559 Views)

Be warned that if the pack pragma is used to pack structures (as is quite often the case when creating code to split comms packets, or when saving space), doubles within a structure may not be on 8-byte boundaries. e.g. in:

 

#pragma pack(1)

struct {

    char x;

    double y;

} fred;

 

fred.y is unlikely to be on an 8-byte boundary.

 

Also, if you're not going to bother with critical sections or other locking mechanisms, variables shared between threads should be declared volatile to prevent compiler optimisation from caching the variable in a register.

 

--
Martin
Certified CVI Developer
0 Kudos
Message 7 of 10
(4,530 Views)

Good points.

 

But, if the double is a simple top level variable (i.e. global), or a top level static variable, I wouldn't think the compiler could use a register.  For multi-thread access, I'm trying to think of any other scenario where the double would be visible to more than one thread without being a top level variable for a writer-reader problem (one thread writing while another reading).

 

A block scope variable goes on the stack, and each thread gets its own stack so no problems there.

 

And with multi-core machines it can get trickier - you can have true concurrency, where as with single core or hyperthreaded machines you get only pseudo-concurrency.

0 Kudos
Message 8 of 10
(4,495 Views)

The compiler can use registers to cache variables. Consider a simple program like:

 

 

double fred = 9999.0;

void myfunc(void)
{
    for (fred=0.0; fred<100.0; fred+=0.5)
        printf("%g\n", fred);
}

 

 

An optimising compiler might choose to cache the value of fred in a register whilst in myfunc(), so that the value of fred in memory only changes from the initial value of 9999.0 to 100.0 when myfunc() returns. A second thread would not see the value of fred change until myfunc exits. Declaring fred as volatile would cure this problem (but might result in a reduction in speed of execution, of course).

--
Martin
Certified CVI Developer
0 Kudos
Message 9 of 10
(4,484 Views)

I might buy your argument if the top level identifier fred was static, but it's not.

 

The compiler can't know at the time it compiles that module, what other modules might be accessing fred.   fred gets exported to the linker, and other modules can be bound to it.

 

The compiler can't know when compiling this module whether or not another module accessing fred is compiled with the same compiler, or if the same compiler, the same optimizations.

 

I don't believe any well designed compiler is going to optimize a non-static top level identifier into a register.

 

Some sources claim the volatile type qualifier isn't of any real use in multi-threading situations, that it's not portable.

 

0 Kudos
Message 10 of 10
(4,462 Views)