简体   繁体   中英

C: Using pthreads and program is not exiting a for loop

I am simulating a device that will receive bytes of data and write to a register when the clock has a falling edge. I've created a seperate pthread that will account for shifting the clock between high and low.

Now my issue is that in the main thread I have the console ask the user to type a hex value to write to the "device" and it then it calls a SendCommand(uint32_t addr, uint16_t data) function to do that. Since it is supposed to send one bit at a time per clock cycle, I have it in a for loop. Here is the send command function:

void SendCmd(uint32_t loadAddr, uint16_t data)
{
    dest = &loadAddr;
    int i;
    printf("%d\n\n",status);
    for(i=15; i>=0; --i) {
        pthread_cond_wait(&rising_edge, &data_lock);
        *dest = (*dest << 1)|(data & 0x8000) >> 15;
               //     ^^^^^^^^ get MSB
               //               ^^^^^ move the MSB down to the LSB, assuming the
               //                     peripheral wants the bit in the LSB.
        pthread_cond_wait(&falling_edge, &data_lock);
        data <<= 1;
        printf("%d\ti=%d\n",*dest,i);
    }
    pthread_mutex_unlock(&data_lock);
    status = ENABLED_IDLE;
}

When i=0, the loop should exit and return back to the main function where it will ask the user to enter another hex value. But it doesnt, and I can't seem to find why it would be stuck before exiting the loop.

EDIT: The freeze is actually occurring before the function ever executes:

int main()
{
    State status = DISABLED;
    Clock clk = LOW;
    int exit_flag = 0;
    char Command[20];
    pthread_t clk_t;
    pthread_cond_init(&en_sig, NULL);
    pthread_cond_init(&rising_edge, NULL);
    pthread_cond_init(&falling_edge, NULL);
    pthread_mutex_init(&clk_lock, NULL);
    pthread_mutex_init(&data_lock, NULL);
    pthread_create(&clk_t, NULL, simClk, NULL);
    while(!exit_flag)
    {
        if(status != ENABLED_ACTIVE)
        {
            fputs("(enable/disable/write [addr] [word_0] [word_1*]/quit): ", stdout);
            fflush(stdout);
            if ( fgets(Command, sizeof Command, stdin) != NULL )
            {
                char *newline = strchr(Command, '\n');
                if ( newline != NULL )
                {
                    *newline = '\0';
                }
            }

            if(strcasecmp(Command,"quit")==0)
            {
                printf("\nShutting Down!\n\n");
                pthread_cancel(&clk_t);
                pthread_mutex_destroy(&clk_lock);
                exit_flag = ~exit_flag;
                continue;
            }

            if(strcasecmp(Command,"enable")==0)
            {
                if(status != DISABLED)
                {
                    printf("\nSynthesizer is already enabled!\n\n");
                    continue;
                }
                status = ENABLED_IDLE;
                nanosleep(&ecsWait, NULL);
                printf("\nEnabled!\n\n");
                pthread_cond_signal(&en_sig);
                continue;
            }

            if(strcasecmp(Command,"disable")==0)
            {
                status = DISABLED;
               // pthread_mutex_lock(&clk_lock);
                printf("\nDisabled!\n\n");
                continue;
            }

            if(strcasecmp(Command,"w")==0)
            {
                if(status != ENABLED_IDLE)
                {
                    printf("\nSynthesizer is not enabled!\n\n");
                    continue;
                }
                printf("\nWriting!\n\n");
                status = ENABLED_ACTIVE;      //FREEZE OCCURS HERE!
                SendCmd(NREGISTER_ADDR,0xF13F);
                continue;
            }

            printf("Invalid command!\n");
        }
   }
    return 0;

}

The issue: the main thread needs to call pthread_cond_wait before the other thread calls pthread_cond_signal . If the other thread signals the condition before the main thread is waiting for the condition, then pthread_cond_wait will never return.

So you need to make sure that things happen in the proper order, and that's where the mutex comes in. You should lock the mutex before creating the other thread, and only unlock the mutex when you are finished using the condition variable. The other thread needs to lock the mutex, signal the condition, and unlock the mutex.

Pseudo code for the main thread

init mutex
lock the mutex
init condition variable
create the other thread
while ( !done )
{
   wait for condition
   do something useful after the condition is signaled 
}
unlock the mutex

Pseudo code for the other thread when it wants to signal the condition

lock the mutex
signal the condition 
unlock the mutex

Obvious question: "But if the main thread always has the mutex locked, how will the other thread ever get the mutex?". Answer: " pthread_cond_wait internally unlocks the mutex, that's why you pass the mutex to pthread_cond_wait ."

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM