【问题标题】:C: Using pthreads and program is not exiting a for loopC: 使用 pthreads 并且程序没有退出 for 循环
【发布时间】:2014-10-09 17:49:58
【问题描述】:

我正在模拟一个设备,它会在时钟下降沿时接收数据字节并写入寄存器。我创建了一个单独的 pthread 来解释时钟在高低之间的转换。

现在我的问题是,在主线程中,我让控制台要求用户输入十六进制值以写入“设备”,然后它调用 SendCommand(uint32_t addr, uint16_t data) 函数来执行此操作。由于它应该在每个时钟周期一次发送一位,因此我将它放在一个 for 循环中。这里是发送命令函数:

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;
}

当 i=0 时,循环应该退出并返回到主函数,它会要求用户输入另一个十六进制值。但它没有,我似乎无法找到为什么它会在退出循环之前被卡住。

编辑:冻结实际上是在函数执行之前发生的:

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;

}

【问题讨论】:

  • dest = &amp;loadAddr 看起来不正确,这意味着您正在写入局部变量loadAddr 的地址。如果loadAddr 是一个实际地址,也许你打算写类似volatile uint8_t *dest = (uint8_t *) loadAddr 的东西。
  • 您是否看到每次调用有 16 行输出?
  • pthread_mutex_lock(&amp;data_lock) 在哪里?在同一个函数中匹配成对的锁和解锁通常是个好主意
  • pthread_cond_wait() 的文档部分说“应在调用线程或未定义行为结果锁定的情况下调用 [互斥锁]”。看起来您遇到的 UB 包含 pthread_cond_wait() 永远不会返回。
  • 当你调用pthread_cond_wait()时你应该持有互斥锁,但如果你已经持有它就不需要再次获取它。事实上,尝试这样做可能会导致程序死锁,具体取决于互斥体的属性。看起来您应该在循环开始之前锁定互斥锁一次,而不是在函数的其他地方。正如@dohashi 观察到的那样,一个互斥锁的获取与一个互斥锁的释放是配对的。

标签: c for-loop pthreads


【解决方案1】:

问题:主线程需要调用pthread_cond_wait其他线程调用pthread_cond_signal。如果其他线程在主线程等待条件之前发出条件信号,那么pthread_cond_wait 将永远不会返回。

所以你需要确保事情以正确的顺序发生,这就是互斥锁的作用所在。你应该在创建另一个线程之前锁定互斥锁,并且只有在你解锁互斥锁时才解锁。使用条件变量完成。另一个线程需要锁定互斥体、发出条件信号并解锁互斥体。

主线程的伪代码

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

另一个线程想要发出条件信号时的伪代码

lock the mutex
signal the condition 
unlock the mutex

明显的问题:“但是如果主线程总是锁定互斥锁,那么其他线程将如何获得互斥锁?”。答案:“pthread_cond_wait 在内部解锁互斥锁,这就是您将互斥锁传递给 pthread_cond_wait 的原因。”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    相关资源
    最近更新 更多