我正在尝试编写一个程序,可以防止在阻塞系统调用时永远停止。请注意,我不是试图解决停止问题。程序应该尝试调用阻塞系统调用,然后在超过给定时间间隔后给予。
我试过写一个程序,在这个程序中我产生一个线程,这个线程试图执行可能永远阻塞的系统调用。MAIN线程等待一个指定的时间间隔,等待所产生的线程完成。如果超过了这个时间间隔,MAIN线程应该给予并继续处理其他紧迫的事情。
在下面的代码中,MAIN线程派生了一个分离的线程来完成这项工作。这是为了避免不得不加入一个可能永远停止的线程。
接下来,MAIN线程等待派生线程使用pthread_cond_timedwait
发出的条件(“I 'm finished!”),以便在超过指定的时间间隔(作为程序参数给出)后超时。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
struct ThreadData {
pthread_attr_t attr;
pthread_t thread;
pthread_cond_t cond;
pthread_mutex_t mutex;
bool result;
};
static void *ThreadRoutine(void *data) {
struct ThreadData *thread_data = data;
puts("THREAD: Locking mutex");
int ret = pthread_mutex_lock(&thread_data->mutex);
if (ret != 0) {
printf("THREAD: Failed to lock mutex: %s\n", strerror(ret));
return NULL;
}
/* Also tried setting cancel state to async, but it did not help */
// puts("THREAD: Setting cancel state enable");
// ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
// if (ret != 0) {
// printf("Failed to set cancel state enable: %s\n", strerror(ret));
// return NULL;
// }
// puts("THREAD: Setting cancel type async");
// ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
// if (ret != 0) {
// printf("THREAD: Failed to set cancel type async: %s\n", strerror(ret));
// return NULL;
// }
puts("THREAD: Blocking for 3 sec");
sleep(3); /* example blocking syscall */
thread_data->result = true;
puts("THREAD: Signalling main thread");
ret = pthread_cond_signal(&thread_data->cond);
if (ret != 0) {
printf("THREAD: Failed to signal main thread: %s\n", strerror(ret));
return NULL;
}
puts("THREAD: Unlocking mutex");
ret = pthread_mutex_unlock(&thread_data->mutex);
if (ret != 0) {
printf("THREAD: Failed to unlock mutex: %s\n", strerror(ret));
return NULL;
}
puts("THREAD: Returning from thread routine");
return NULL;
}
int main(int argc, char **argv) {
if (argc <= 1) {
puts("Missing argument");
return EXIT_FAILURE;
}
const int timeout = atoi(argv[1]);
struct ThreadData thread_data;
thread_data.result = false;
puts("MAIN: Initializing mutex");
int ret = pthread_mutex_init(&thread_data.mutex, NULL);
if (ret != 0) {
printf("MAIN: Failed to initialize mutex: %s\n", strerror(ret));
return EXIT_FAILURE;
}
puts("MAIN: Initializing condition");
ret = pthread_cond_init(&thread_data.cond, NULL);
if (ret != 0) {
printf("MAIN: Failed to initialize condition: %s\n", strerror(ret));
return EXIT_FAILURE;
}
puts("MAIN: Locking mutex");
ret = pthread_mutex_lock(&thread_data.mutex);
if (ret != 0) {
printf("MAIN: Failed to lock mutex: %s\n", strerror(ret));
return EXIT_FAILURE;
}
puts("MAIN: Initializing thread attributes");
ret = pthread_attr_init(&thread_data.attr);
if (ret != 0) {
printf("Failed to initialize thread attributes\n");
return EXIT_FAILURE;
}
puts("MAIN: Setting thread detach state");
ret = pthread_attr_setdetachstate(&thread_data.attr, PTHREAD_CREATE_DETACHED);
if (ret != 0) {
printf("MAIN: Failed to set thread detach state: %s\n", strerror(ret));
return EXIT_FAILURE;
}
puts("MAIN: Creating thread");
ret = pthread_create(&thread_data.thread, &thread_data.attr, &ThreadRoutine, &thread_data);
if (ret != 0) {
printf("MAIN: Failed to create thread: %s\n", strerror(ret));
return EXIT_FAILURE;
}
puts("MAIN: Destroying thread attributes");
ret = pthread_attr_destroy(&thread_data.attr);
if (ret != 0) {
printf("MAIN: Failed to destroy thread attributes: %s\n", strerror(ret));
return EXIT_FAILURE;
}
puts("MAIN: Calculating timeout interval");
struct timespec ts = {0};
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
printf("MAIN: Failed to get current time: %s\n", strerror(errno));
return EXIT_FAILURE;
}
ts.tv_sec += timeout;
printf("MAIN: Waiting for thread to finish (timeout: %d sec)\n", timeout);
ret = pthread_cond_timedwait(&thread_data.cond, &thread_data.mutex, &ts);
switch (ret) {
case 0:
printf("MAIN: Thread finished in time; computation evaluated to %s\n", (thread_data.result) ? "true" : "false");
return EXIT_SUCCESS;
case ETIMEDOUT:
puts("MAIN: Thread did not finish in time");
return EXIT_SUCCESS;
default:
printf("MAIN: Failed to wait for thread to finish: %s", strerror(ret));
return EXIT_FAILURE;
}
}
运行此程序时,看起来它在pthread_cond_timedwait
上被阻塞的时间超过了指定的超时间隔。
$ gcc -g -Wall -Wextra -c main.c -o main.o
$ gcc main.o -o prog -pthread
$ time ./prog 1
MAIN: Initializing mutex
MAIN: Initializing condition
MAIN: Locking mutex
MAIN: Initializing thread attributes
MAIN: Setting thread detach state
MAIN: Creating thread
MAIN: Destroying thread attributes
MAIN: Calculating timeout interval
MAIN: Waiting for thread to finish (timeout: 1 sec)
THREAD: Locking mutex
THREAD: Blocking for 3 sec
THREAD: Signalling main thread
THREAD: Unlocking mutex
THREAD: Returning from thread routine
MAIN: Thread did not finish in time
./prog 1 0.00s user 0.00s system 0% cpu 3.007 total
程序正确地输出线程没有及时完成。但是根据time
命令,主线程似乎仍然被阻塞,直到派生线程完成。虽然我希望man线程在超过超时间隔后继续。
我不知道如何使用线程来实现它。另一个选择是尝试使用fork
来实现它。但是如果可能的话,我宁愿使用线程。
谢谢:)
1条答案
按热度按时间yws3nbqq1#
正如@Shawn
pthread_cond_timedwait
提到的,必须重新获取互斥锁。通过在调用“可能永远”阻塞系统调用之前释放派生线程中的互斥锁,代码可以按预期工作。谢谢:)执行时间现在大约是1秒,正如我所预期的。