3

All

I have a question about pthread_cond_wait(). In short, I create two POSIX thread in a process, If I execute the following code, why is cpu utilization full?

I take experiments on it, if I remove comment mark before bool isNodeConnect3, the program seems to be no probelm, CPU utilization is almost 0%, in other words, theads will go to sleep and don't spend CPU resource, that's what I want.

Is it a data algnment probelm? maybe, but I don't think so, because I bracket my struct by "#pragma pack(push,1) ... #pragma (pop)" Could you give me suggestion??

Environment Host OS is win7/intel 64 bit, guest OS is ubuntu 10.04LTS Give "number of processor cores:4" to guest OS The following is my test code, you can build and run it by
gcc -o program1 program1.c -pthread && ./program1 Get CPU utilization is 25%. Result depends on your setting.

Thanks a lot.

Code

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <errno.h>
#include <stdbool.h>


#pragma pack(push,1)
struct BUFF_TX{
    pthread_mutex_t mutex_lock;
    pthread_cond_t more;
};

struct AtreeNode{
    struct BUFF_TX buff_tx;

    bool isNodeConnect;                   
    bool isNodeConnect1;                  
    bool isNodeConnect2;                  
//  bool isNodeConnect3;  // important           

    pthread_t thrd_tx;          

};


struct AtreeNode treeNode[2];
int tmp[2];  

#pragma (pop)


void Thread_TX(int *nodeIdx)
{
    int idx    = *nodeIdx;

    while(1)
    {

        printf("Thread %d enter mutex lock...\n", idx);
        pthread_mutex_lock(&treeNode[idx].buff_tx.mutex_lock);       
        while(1)
        {
            if(idx==0)
            {
                printf("idx==0 wait...\n");
                pthread_cond_wait(&(treeNode[0].buff_tx.more), &treeNode[idx].buff_tx.mutex_lock);
            }
            else if(idx==1)
            {
                printf("idx==1 wait...\n");
                pthread_cond_wait(&(treeNode[1].buff_tx.more), &treeNode[idx].buff_tx.mutex_lock);
            }
            else
                printf("err\n");

        }
        pthread_mutex_unlock(&treeNode[idx].buff_tx.mutex_lock);            
        printf("Thread %d leave mutex lock...\n", idx);

    }

}




int main(int argc, char *argv[])
{
    int i;
    int ret;

    tmp[0] = 0;
    tmp[1] = 1;


    for(i=0; i<2; i++)
    {
        if(pthread_cond_init(&treeNode[i].buff_tx.more, NULL) != 0)
        {
            printf("cond %d init fail.\n", i);
            exit(EXIT_FAILURE);
        }

        if(pthread_mutex_init(&treeNode[i].buff_tx.mutex_lock, NULL) != 0)
        {
            printf("mutex lock %d init fail.\n", i);
            exit(EXIT_FAILURE);
        }
    }

    for(i=0; i<2; i++)
    {   
        ret = pthread_create(&treeNode[i].thrd_tx, NULL, (void *)Thread_TX, (void *)(&tmp[i]));
        if(ret) 
        {
            printf("pthread_create thrd_tx %d err\n", i);
            return false;
        }
    }

    pthread_join(treeNode[0].thrd_tx, NULL);
    pthread_join(treeNode[1].thrd_tx, NULL);

    exit(EXIT_SUCCESS);
}
MOMOSir
  • 31
  • 1
  • 2
  • "maybe, but I don't think so". Have you tried to remove it and see what happens? Just don't use `#pragma pack`. The results may be not *that* good. Alignment is here for a reason. By the way `#pragma(pop)` is incorrect and `-Wall` would have told you so. – n. m. could be an AI Mar 04 '14 at 08:55
  • Thanks for your response.n.m. I change tags to #pragma pack(push,1) #pragma pack(pop) after turn on -Wall option to see message, the result is still as same. Before I post this question, I had tried to remove alignment tags for enabling or disabling alignment. Everything is ok that I printed variable address or sizeof. Maybe I have something wrong........hehe... – MOMOSir Mar 04 '14 at 09:06

1 Answers1

6

Remove #pragma pack(1) and forget you ever heard of it. Your problem is that you are passing an invalid pointer to pthread_cond_wait. pthread_cond_t has a particular alignment requirement and you are creating objects which are not necessarily aligned to that requirement, and thus their addresses are not valid to pass to pthread_cond_wait. See also https://sourceware.org/bugzilla/show_bug.cgi?id=16549 which was RESOLVED by being MOVED to a bug report against GCC for not catching the invalid pointer usage.

You should be able to confirm whether this is the actual cause of your issue by running your program under strace -f and seeing that the futex syscalls are failing with EINVAL or similar.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • Normal thread safety rules only apply to properly-aligned types. Since your types are packed, normal thread safety rules don't apply to them, they are free to tear. You can't ever let one thread touch any part of an unaligned object while another thread is or might be modifying it. This makes your lock and condition variable unusable. – David Schwartz Mar 04 '14 at 13:02
  • This has nothing to do with thread-safety rules. It applies even to things unrelated to threads. For example, in a packed structure where `foo.x` is a misaligned int, `scanf("%d", &foo.x)` invokes undefined behavior. – R.. GitHub STOP HELPING ICE Mar 04 '14 at 16:08
  • What has nothing to do with thread-safety rules? I'm talking about thread-safety rules, which obviously has something to do with thread-safety rules. Even if he was only calling his own functions that all took packed structures or pointers to them, he'd still have the thread-safety issue that I'm talking about. – David Schwartz Mar 04 '14 at 18:45
  • Except that's not the issue OP is having. – R.. GitHub STOP HELPING ICE Mar 04 '14 at 18:53
  • Still, he needs to understand all the serious bugs in his code, don't you think? – David Schwartz Mar 04 '14 at 18:57
  • I admit I didn't spend a lot of time reviewing the code, but I didn't spot any bugs except the misaligned `pthread_cond_t`. What other serious bugs are you referring to? – R.. GitHub STOP HELPING ICE Mar 04 '14 at 19:01
  • @R.. A platform that has `#pragma pack` probably does define *some* behaviour beyond what's defined by the standard when it comes to unaligned access. One would have to consult the platform documentation for details about what is and is not allowed. – n. m. could be an AI Mar 04 '14 at 19:12
  • @n.m.: This is an interesting claim. Unfortunately, what happened is that `#pragma pack` originated on compilers for specific machines (8086) where (1) misaligned accesses were permitted by the hardware, and (2) the compilers were too stupid to make any transformations that might care if the access is aligned. GCC then copied this feature into a compiler which supports all kinds of cpu architectures, most of which do not support misaligned accesses. It was able to give the right semantics when accessing the misaligned object directly where it can tell it's misaligned... – R.. GitHub STOP HELPING ICE Mar 04 '14 at 19:36
  • ...but it's unable to provide access to the misaligned object to external functions to which its address is passed without making all indirect (via pointer) accesses, everywhere, in the whole program, very slow and bloated (GCC actually does have an *option* to do this at least on ARM, and scarily, some people actually use it!). In any case, the glibc folks are opening a bug report against GCC requesting that misaligned objects have their misalignment encoded as part of their type so that (`&foo.misaligned_int`) has a type that cannot implicitly convert to `int *`, etc. – R.. GitHub STOP HELPING ICE Mar 04 '14 at 19:38