pthreadコールバックはユーザー入力を中断します
質問
独自のstop_watchモジュールを作成しました。これにより、スレッドが作成され、しばらくの間スリープ状態になります。秒が経過すると、main.cでコールバック関数を呼び出し、ユーザーに時間の期限が切れたことを通知します。
これは、ユーザーが数字を入力するのに3秒しかなく、5桁を入力する必要があるようにするためです。時間切れになると、プログラムを停止する必要があります。
2つの問題。 1)必要な時間内に数字を入力した場合。スレッドをキャンセルするにはどうすればよいですか。 thread_killまたはthread_cancelの使用を考えていましたか? 2)do_whileループでどのように終了できますか?ユーザーの入力を待っている間、scanfがブロックするため。
ご提案ありがとうございます
以下の私のコード:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include "stop_watch.h"
struct data_struct *g_data_struct;
void timeout_cb(int id)
{
printf("Digit timeout\n");
free(g_data_struct);
}
int main()
{
pthread_t thread_id;
unsigned int digit = 0;
g_data_struct = (struct data_struct*) calloc(1, sizeof(*g_data_struct));
if(!g_data_struct)
{
printf("=== failed to allocate memory ===\n");
return 0;
}
/* start timer for 3 seconds */
g_data_struct->seconds = 3;
g_data_struct->func_ptr = timeout_cb;
thread_id = start_stopwatch(g_data_struct);
do
{
printf("Enter digit: ");
scanf("%d", &digit);
}while(1);
pthread_join(thread_id, NULL);
printf("=== End of Program - all threads in ===\n");
free(g_data_struct);
return 0;
}
#include <stdio.h>
#include <pthread.h>
#include "stop_watch.h"
pthread_t thread_id;
static id = 10;
/* start sleeping and call the callback when seconds have expired */
static void* g_start_timer(void *args)
{
void (*function_pointer)(int id);
int seconds = ((struct data_struct*) args)->seconds;
function_pointer = ((struct data_struct*) args)->func_ptr;
sleep(seconds);
(void) (*function_pointer)(id);
pthread_exit(NULL);
return 0;
}
/* Will sleep in its own thread for a period of seconds */
int start_stopwatch(struct data_struct *g_data_struct)
{
int rc = 0;
int seconds = g_data_struct->seconds;
printf("=== start_stopwatch(): %d\n", seconds);
rc = pthread_create(&thread_id, NULL, g_start_timer, (void *) g_data_struct);
if(rc)
{
printf("=== Failed to create thread\n");
return 1;
}
return thread_id;
}
この質問は、C99 gccに関するものです。
解決
最初にこれに別のスレッドを使用することはお勧めしません。しかし、スレッドの使用方法を学ぶことは演習のように見えるので、私はそれに取り組みます。
数字が入力されたかどうかを示すグローバルブールフラグを設定できます。 g_start_timerで、function_pointerを呼び出す直前に、フラグが設定されているかどうかを確認します。その場合、関数を呼び出さないでください。
スレッドのスリープ期間が終了する前にスレッドを早く終了させたい場合は、ロックをロックしてミューテックスを使用できます。
編集:あなたはそれが運動ではないと言っているので、私はそれをどうするかについて言及します。 select()やpoll()など、stdinでの入力を待機中にタイムアウトする可能性のある関数を使用します。または、alarm()を使用して中断します。アラームの使用例を次に示します。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
void alarm_signal(int signum)
{
}
int main()
{
char c;
unsigned int v = 0;
struct sigaction act;
puts("Enter digit: ");
/* Register dummy handler for alarm */
act.sa_handler = &alarm_signal;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM, &act, NULL);
/* Set timer for 3 seconds */
alarm(3);
/* Read the digits */
errno = 0;
while(0 != read(STDIN_FILENO, &c, 1))
{
if(c < '0' || c > '9')
break;
v = v*10 + c - '0';
}
if(errno == EINTR)
puts("Timed out");
else
printf("Value is %d\n", v);
return 0;
}
他のヒント
もちろん、thread_cancelを使用してスレッドをキャンセルできます。 scanfに関しては、パイプを使用して端末からの入力をシミュレートすることを考えるかもしれません。