【问题标题】:Pthread runtime errorsPthread 运行时错误
【发布时间】:2014-05-26 00:44:01
【问题描述】:

我在调试我编写的以下程序时遇到问题。这个想法是有两个单独的线程;一个线程执行 5 秒倒计时,而另一个线程等待用户的键输入。无论哪个线程先完成,都应该取消同级线程并退出程序。但是,下面的代码只是挂起。

任何帮助将不胜感激,但我将非常感谢您对问题的解释。

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // For sleep()

#define NUM_THREADS 2

// The stuct to be passed as an argument to the countdown routine
typedef struct countdown_struct {
pthread_t *thread;
signed int num_secs;
} CountdownStruct;

// Struct for passing to the input wait routine
typedef struct wait_struct {
pthread_t *thread;
int *key;
} WaitStruct;

// Countdown routine; simply acts as a timer counting down
void * countdown(void *args)
{
CountdownStruct *cd_str = (CountdownStruct *)args;
signed int secs = cd_str->num_secs;
printf("Will use default setting in %d seconds...", secs);
while (secs >= 0)
{
    sleep(1);
    secs -= 1;
    printf("Will use default setting in %d seconds...", secs);
}

// Cancel the other struct
pthread_cancel(*(cd_str->thread));
return NULL;
}

// Waits for the user to pass input through the tty
void * wait_for_input(void *args)
{
WaitStruct *wait_str = (WaitStruct *) args;
int c = 0;
do {
    c = getchar();
} while (!(c == '1' || c == '2'));
*(wait_str->key) = c;

// Cancel the other thread
pthread_cancel(*(wait_str->thread));
return NULL;
}

int main(int argc, char **argv)
{
pthread_t wait_thread;
pthread_t countdown_thread;
pthread_attr_t attr;
int key=0;
long numMillis=5000;
int rc=0;
int status=0;

// Create the structs to be passe as paramaters to both routines
CountdownStruct *cd_str = (CountdownStruct *) malloc(sizeof(CountdownStruct));
if (cd_str == NULL)
{
    printf("Couldn't create the countdown struct. Aborting...");
    return -1;
}
cd_str->thread = &wait_thread;
cd_str->num_secs = 5;

WaitStruct *wait_str = (WaitStruct *) malloc(sizeof(WaitStruct));
if (wait_str == NULL)
{
    printf("Couldn't create the iput wait struct. Aborting...");
    return -1;
}
wait_str->thread = &countdown_thread;
wait_str->key = &key;

// Create the joinable attribute
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

// Create both threads
rc = pthread_create(&countdown_thread, &attr, countdown, (void *) cd_str);
if (rc) { printf("Error with the thread creation!"); exit(-1); }
rc = pthread_create(&wait_thread, &attr, wait_for_input, (void *) wait_str);
if (rc) { printf("Error with the thread creation!"); exit(-1); }

// Destroy the pthread_attribute
pthread_attr_destroy(&attr);

// now join on the threads and wait for main
pthread_join(wait_thread, NULL);
pthread_join(countdown_thread, NULL);

// Call pthread_exit
pthread_exit(NULL);

// Free the function structs
free(cd_str);
free(wait_str);
}

【问题讨论】:

  • 我注意到在几个地方,包括stackoverflow.com/questions/433989/posix-cancellation-points getchar() 不需要是取消点。我想在标准输入上做一个选择会给你超时和读取。
  • @dennis 即使调用 getchar() 超时线程也永远不会完成并关闭程序。这是最令人费解的一点。感谢您的帮助,但 select() 是一种解决方法,不能解决此处所述的问题
  • 你的意思是没有 getchar() 调用?然后 wait_for_input 线程将处于自旋循环中并且永远不会达到取消点。连接会挂起,阻止 main 退出。还是您只是让 wait_for_input 循环失败?
  • 剪切并粘贴到我的 Fedora 19 机器上,编译,超时后退出。 (数到 -1,但足够接近。)
  • @dennis 我失败了。这很奇怪;超时循环不会为我退出。我在 Mac 上运行,这可能是平台问题吗?我现在试试你的答案,看看它是否适合我

标签: c multithreading pthreads


【解决方案1】:

Getchar 不需要是取消点。 select 和 pselect 是。即使您想继续使用倒计时线程,您仍然可以使用 select 在对方线程中提供取消点。

我对以下修改后的 wait_for_input() 有合理的行为

    // Waits for the user to pass input through the tty
    void * wait_for_input(void *args)
    {
      WaitStruct *wait_str = (WaitStruct *) args;
      int c = 0;
      fd_set  readFds;
      int numFds=0;
      FD_ZERO(&readFds);

      do {
        struct timeval timeout={.tv_sec=8,.tv_usec=0};
        /* select here is primarily to serve as a cancellation
         * point.  Though there is a possible race condition
         * still between getchar() getting called right as the
         * the timeout thread calls cancel.(). 
         * Using the timeout option on select would at least 
         * cover that, but not done here while testing. 
         *******************************************************/  
        FD_ZERO(&readFds);
        FD_SET(STDOUT_FILENO,&readFds);
        numFds=select(STDOUT_FILENO+1,&readFds,NULL,NULL,&timeout);
        if(numFds==0 )  
        {
          /* must be timeout if no FD's selected */
          break;
        }
        if(FD_ISSET(STDOUT_FILENO,&readFds))
        {
          printf("Only get here if key pressed\n");
          c = getchar();
        }  
      } while (!(c == '1' || c == '2'));
      *(wait_str->key) = c;
      // Cancel the other thread
      pthread_cancel(*(wait_str->thread));
      return NULL;
    }

【讨论】:

  • 解决方案对我有用。公平点就计为-1。如果没有返回字符,Printf 也不会刷新。我是在凌晨 2 点写的,但如果这是一个正当的借口 ;-) 再次感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-25
  • 1970-01-01
  • 2017-11-20
  • 2015-12-17
  • 1970-01-01
  • 2014-03-26
相关资源
最近更新 更多