在不使用条件变量或其他各种同步原语的情况下暂停线程执行
Pause thread execution without using condition variable or other various synchronization pritmives
问题
我希望能够暂停来自不同线程的线程的执行。注意暂停的线程不应该合作。目标线程的暂停不必在暂停线程想要暂停时立即发生。允许延迟暂停。
我似乎找不到这方面的任何信息,因为所有搜索都为我提供了使用条件变量的结果...
想法
- 使用调度程序和内核系统调用来阻止线程再次被调度
- 使用调试器系统调用停止目标线程
OS-不可知论是可取的,但不是必需的。这可能非常 OS 依赖,因为打乱调度和线程是一个非常低级的操作。
在 Unix-like OS 上,有 pthread_kill()
将信号传送到指定的线程。您可以安排该信号有一个处理程序,该处理程序等待直到以某种方式被告知才能恢复。
这是一个简单的例子,“暂停”只是在恢复之前休眠一段固定的时间。 Try on godbolt.
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
void safe_print(const char *s) {
int saved_errno = errno;
if (write(1, s, strlen(s)) < 0) {
exit(1);
}
errno = saved_errno;
}
void sleep_msec(int msec) {
struct timespec t = {
.tv_sec = msec / 1000,
.tv_nsec = (msec % 1000) * 1000 * 1000
};
nanosleep(&t, NULL);
}
void *work(void *unused) {
(void) unused;
for (;;) {
safe_print("I am running!\n");
sleep_msec(100);
}
return NULL;
}
void handler(int sig) {
(void) sig;
safe_print("I am stopped.\n");
sleep_msec(500);
}
int main(void) {
pthread_t thr;
pthread_create(&thr, NULL, work, NULL);
sigset_t empty;
sigemptyset(&empty);
struct sigaction sa = {
.sa_handler = handler,
.sa_flags = 0,
};
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
for (int i = 0; i < 5; i++) {
sleep_msec(1000);
pthread_kill(thr, SIGUSR1);
}
pthread_cancel(thr);
pthread_join(thr, NULL);
return 0;
}
问题
我希望能够暂停来自不同线程的线程的执行。注意暂停的线程不应该合作。目标线程的暂停不必在暂停线程想要暂停时立即发生。允许延迟暂停。
我似乎找不到这方面的任何信息,因为所有搜索都为我提供了使用条件变量的结果...
想法
- 使用调度程序和内核系统调用来阻止线程再次被调度
- 使用调试器系统调用停止目标线程
OS-不可知论是可取的,但不是必需的。这可能非常 OS 依赖,因为打乱调度和线程是一个非常低级的操作。
在 Unix-like OS 上,有 pthread_kill()
将信号传送到指定的线程。您可以安排该信号有一个处理程序,该处理程序等待直到以某种方式被告知才能恢复。
这是一个简单的例子,“暂停”只是在恢复之前休眠一段固定的时间。 Try on godbolt.
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
void safe_print(const char *s) {
int saved_errno = errno;
if (write(1, s, strlen(s)) < 0) {
exit(1);
}
errno = saved_errno;
}
void sleep_msec(int msec) {
struct timespec t = {
.tv_sec = msec / 1000,
.tv_nsec = (msec % 1000) * 1000 * 1000
};
nanosleep(&t, NULL);
}
void *work(void *unused) {
(void) unused;
for (;;) {
safe_print("I am running!\n");
sleep_msec(100);
}
return NULL;
}
void handler(int sig) {
(void) sig;
safe_print("I am stopped.\n");
sleep_msec(500);
}
int main(void) {
pthread_t thr;
pthread_create(&thr, NULL, work, NULL);
sigset_t empty;
sigemptyset(&empty);
struct sigaction sa = {
.sa_handler = handler,
.sa_flags = 0,
};
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
for (int i = 0; i < 5; i++) {
sleep_msec(1000);
pthread_kill(thr, SIGUSR1);
}
pthread_cancel(thr);
pthread_join(thr, NULL);
return 0;
}