Linux 线程挂起/恢复

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11468333/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 13:48:13  来源:igfitidea点击:

Linux Threads suspend/resume

clinuxmultithreadingpthreads

提问by ZeeAzmat

I'm writing a code in which I have two threads running in parallel.

我正在编写一个代码,其中有两个并行运行的线程。

1st is the main thread which started the 2nd thread. 2nd thread is just a simple thread executing empty while loop.

第一个是启动第二个线程的主线程。第二个线程只是一个执行空 while 循环的简单线程。

Now I want to pause / suspend the execution of 2nd thread by 1st thread who created it. And after some time I want to resume the execution of 2nd thread (by issuing some command or function) from where it was paused / suspended.

现在我想暂停/暂停创建它的第一个线程的第二个线程的执行。一段时间后,我想从暂停/挂起的地方恢复第二个线程的执行(通过发出一些命令或函数)。

回答by Francis Upton IV

As far as I know you can't really just pause some other thread using pthreads. You have to have something in your 2nd thread that checks for times it should be paused using something like a condition variable. This is the standard way to do this sort of thing.

据我所知,您不能真正使用 pthreads 暂停其他一些线程。你必须在你的第二个线程中有一些东西来检查它应该使用条件变量之类的东西暂停的时间。这是做这种事情的标准方法。

回答by aisbaa

You can use mutex to do that, pseudo code would be:

您可以使用互斥锁来做到这一点,伪代码是:

While (true) {
    /* pause resume */
    lock(my_lock); /* if this is locked by thread1, thread2 will wait until thread1 */
                   /* unlocks it */
    unlock(my_lock); /* unlock so that next iteration thread2 could lock */

    /* do actual work here */
}

回答by Jeyaram

There is no pthread_suspend(), pthread_resume() kind of APIs in POSIX.
Mostly condition variables can be used to control the execution of other threads.

POSIX 中没有 pthread_suspend()、pthread_resume() 这类 API。
大多数情况下,条件变量可用于控制其他线程的执行。

The condition variable mechanism allows threads to suspend execution and relinquish the processor until some condition is true. A condition variable must always be associated with a mutex to avoid a race condition created by one thread preparing to wait and another thread which may signal the condition before the first thread actually waits on it resulting in a deadlock.

条件变量机制允许线程暂停执行并放弃处理器,直到某些条件为真。条件变量必须始终与互斥锁相关联,以避免由一个准备等待的线程和另一个可能在第一个线程实际等待它之前发出条件信号的线程创建的竞争条件,从而导致死锁。

For more info

欲了解更多信息

Pthreads

线程

Linux Tutorial Posix Threads

Linux 教程 Posix 线程

回答by Jah

If you can use processes instead, you can send job control signals (SIGSTOP / SIGCONT) to the second process. If you still want to share the memory between those processes, you can use SysV shared memory (shmop, shmget, shmctl...).

如果您可以改用进程,则可以向第二个进程发送作业控制信号 (SIGSTOP / SIGCONT)。如果您仍想在这些进程之间共享内存,则可以使用 SysV 共享内存(shmop、shmget、shmctl...)。

Even though I haven't tried it myself, it might be possible to use the lower-level clone() syscall to spawn threads that don't share signals. With that, you might be able to send SIGSTOP and SIGCONT to the other thread.

即使我自己没有尝试过,也可以使用较低级别的 clone() 系统调用来生成不共享信号的线程。这样,您就可以将 SIGSTOP 和 SIGCONT 发送到另一个线程。

回答by mk..

Not sure if you will like my answer or not. But you can achieve it this way.

不知道你是否会喜欢我的回答。但是你可以通过这种方式实现它。

If it is a separate process instead of a thread, I have a solution(This might even work for thread, maybe someone can share your thoughts) using signals.

如果它是一个单独的进程而不是一个线程我有一个使用信号的解决方案(这甚至可能适用于线程,也许有人可以分享您的想法)。

There is no system currently in placeto pause or resume the execution of the processes. But surely you can build one.

当前没有系统可以暂停或恢复进程的执行。但你肯定可以建造一个。

Steps i would do if i want it in my project:

如果我想在我的项目中使用它,我会做的步骤:

  • Register a signal handler for the second process.

  • Inside the signal handler, wait for a semaphore.

  • Whenever you want to pause the other process, just send in a signal
    that you registered the other process with. The program will go into sleep state.

  • When you want to resume the process, you can send a different signal again. Inside that signal handler, you will check if the semaphore is locked or not. If it is locked, you will release the semaphore. So
    the process 2 will continue its execution.

  • 为第二个进程注册一个信号处理程序。

  • 在信号处理程序中,等待信号量。

  • 每当您想暂停另一个进程时,只需发送一个
    您注册另一个进程的信号即可。程序将进入睡眠状态。

  • 当您想恢复该过程时,您可以再次发送不同的信号。在该信号处理程序中,您将检查信号量是否已锁定。如果它被锁定,您将释放信号量。所以
    进程2将继续执行。

If you can implement this, please do share your feedack, if it worked for you or not. Thanks.

如果您可以实现这一点,请分享您的反馈,无论它是否适合您。谢谢。

回答by Groovy

For implementing the pause on a thread, you need to make it wait for some event to happen. Waiting on a spin-lock mutex is CPU cycle wasting. IMHO, this method should not be followed as the CPU cycles could have been used up by other processes/threads. Wait on a non-blocking descriptor (pipe, socket or some other). Example code for using pipes for inter-thread communicationcan be seen here Above solution is useful, if your second thread has more information from multiple sources than just the pause and resume signals. A top-level select/poll/epoll can be used on non-blocking descriptors. You can specify the wait time for select/poll/epoll system calls, and only that much micro-seconds worth of CPU cycles will be wasted. I mention this solution with forward-thinking that your second thread will have more things or events to handle than just getting paused and resumed. Sorry if it is more detailed than what you asked.

为了在线程上实现暂停,您需要让它等待某个事件发生。等待自旋锁互斥是 CPU 周期浪费。恕我直言,不应遵循此方法,因为其他进程/线程可能已用完 CPU 周期。等待非阻塞描述符(管道、套接字或其他)。使用管道进行线程间通信的示例代码可以在这里看到 上面的解决方案很有用,如果您的第二个线程有来自多个来源的更多信息,而不仅仅是暂停和恢复信号。顶级 select/poll/epoll 可用于非阻塞描述符。您可以指定 select/poll/epoll 系统调用的等待时间,并且只会浪费那么多微秒的 CPU 周期。我提到这个解决方案时有前瞻性,即您的第二个线程将有更多的事情或事件要处理,而不仅仅是暂停和恢复。对不起,如果它比你问的更详细。

Another simpler approach can be to have a shared boolean variable between these threads. Main thread is the writer of the variable, 0 - signifies stop. 1 - signifies resume Second thread only reads the value of the variable. To implement '0' state, use usleep for sime micro-seconds then again check the value. Assuming, few micro-seconds delay is acceptable in your design. To implement '1' - check the value of the variable after doing certain number of operations. Otherwise, you can also implement a signal for moving from '1' to '0' state.

另一种更简单的方法是在这些线程之间共享一个布尔变量。主线程是变量的作者,0 - 表示停止。1 - 表示恢复 第二个线程只读取变量的值。要实现“0”状态,请使用 usleep sime 微秒,然后再次检查该值。假设在您的设计中,几微秒的延迟是可以接受的。实现'1' - 在执行一定数量的操作后检查变量的值。否则,您还可以实现从“1”状态移动到“0”状态的信号。

回答by Groovy

This question is not about how to use mutexes, but how to suspend a thread.

这个问题不是关于如何使用互斥锁,而是关于如何挂起线程。

In Unix specification there is a thread function called pthread_suspend, and another called pthread_resume_np, but for some reason the people who make Linux, FreeBSD, NetBSD and so on have not implemented these functions.

在Unix规范中,有一个线程函数叫做pthread_suspend,另一个叫做pthread_resume_np,但是由于某些原因,Linux、FreeBSD、NetBSD等的开发者没有实现这些函数。

So to understand it, the functions simply are not there. There are workarounds but unfortunately it is just not the same as calling SuspendThread on windows. You have to do all kinds of non-portable stuff to make a thread stop and start using signals.

所以要理解它,函数根本就不存在。有一些解决方法,但不幸的是它与在 Windows 上调用 SuspendThread 不同。您必须做各种不可移植的事情才能使线程停止并开始使用信号。

Stopping and resuming threads is vital for debuggers and garbage collectors. For example, I have seen a version of Wine which is not able to properly implement the "SuspendThread" function. Thus any windows program using it will not work properly.

停止和恢复线程对于调试器和垃圾收集器至关重要。例如,我看到一个版本的 Wine 无法正确实现“SuspendThread”功能。因此任何使用它的 Windows 程序都无法正常工作。

I thought that it was possible to do it properly using signals based on the fact that JVM uses this technique of signals for the Garbage collector, but I have also just seen some articles online where people are noticing deadlocks and so on with the JVM, sometimes unreproducable.

我认为可以根据 JVM 将这种信号技术用于垃圾收集器这一事实来正确使用信号来做到这一点,但我也刚刚在网上看到一些文章,人们注意到 JVM 的死锁等问题,有时不可复制。

So to come around to answer the question, you cannot properly suspend and resume threads with Unix unless you have a nice Unix that implements pthread_suspend_np. Otherwise you are stuck with signals.

因此,为了回答这个问题,除非您有一个很好的 Unix 来实现 pthread_suspend_np,否则您无法使用 Unix 正确挂起和恢复线程。否则你会被信号困住。

The big problem with Signals is when you have about five different libraries all linked in to the same program and all trying to use the same signals at the same time. For this reason I believe that you cannot actually use something like ValGrind and for example, the Boehm GC in one program. At least without major coding at the very lowest levels of userspace.

Signals 的一个大问题是当你有大约五个不同的库都链接到同一个程序并且都试图同时使用相同的信号时。出于这个原因,我相信您实际上不能在一个程序中使用像 ValGrind 这样的东西,例如 Boehm GC。至少在用户空间的最低级别没有主要编码。

Another answer to this question could be. Do what Linuz Torvalds does to NVidia, flip the finger at him and get him to implement the two most critical parts missing from Linux. First, pthread_suspend, and second, a dirty bit on memory pages so that proper garbage collectors can be implemented. Start a large petition online and keep flipping that finger. Maybe by the time Windows 20 comes out, they will realise that Suspending and resuming threads, and having dirty bits is actually one of the fundamental reasons Windows and Mac are better than Linux, or any Unix that does not implement pthread_suspend and also a dirty bit on virtual pages, like VirtualAlloc does in Windows.

这个问题的另一个答案可能是。做 Linuz Torvalds 对 NVidia 所做的事情,对他指手画脚,让他实现 Linux 中缺少的两个最关键的部分。首先,pthread_suspend,其次,内存页面上的脏位,以便可以实现适当的垃圾收集器。在网上发起一个大型请愿活动,然后继续挥动手指。可能等到Windows 20出来的时候,他们会意识到暂停和恢复线程,以及有脏位实际上是Windows和Mac优于Linux的根本原因之一,或者任何没有实现pthread_suspend和脏位的Unix在虚拟页面上,就像 VirtualAlloc 在 Windows 中所做的那样。

I do not live in hope. Actually for me I spent a number of years planning my future around building stuff for Linux but have abandoned hope as a reliable thing all seems to hinge on the availability of a dirty bit for virtual memory, and for suspending threads cleanly.

我并不生活在希望中。实际上,对我来说,我花了很多年时间围绕为 Linux 构建东西来规划我的未来,但已经放弃了希望,因为可靠的事情似乎都取决于虚拟内存的脏位的可用性,以及干净地挂起线程。

回答by user8549285

You can suspend a thread simply by signal

您可以简单地通过信号挂起线程

pthread_mutex_t mutex;
static void thread_control_handler(int n, siginfo_t* siginfo, void* sigcontext) {
    // wait time out
    pthread_mutex_lock(&mutex);
    pthread_mutex_unlock(&mutex);
}
// suspend a thread for some time
void thread_suspend(int tid, int time) {
    struct sigaction act;
    struct sigaction oact;
    memset(&act, 0, sizeof(act));
    act.sa_sigaction = thread_control_handler;
    act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
    sigemptyset(&act.sa_mask);
    pthread_mutex_init(&mutex, 0);
    if (!sigaction(SIGURG, &act, &oact)) {
        pthread_mutex_lock(&mutex);
        kill(tid, SIGURG);
        sleep(time);
        pthread_mutex_unlock(&mutex);
    }
}

回答by shubham

I tried suspending and resuming thread using signals, here is my solution. Please compile and link with -pthread.

我尝试使用信号暂停和恢复线程,这是我的解决方案。请用-pthread 编译和链接。

Signal SIGUSR1 suspends the thread by calling pause()and SIGUSR2 resumes the thread.

信号 SIGUSR1 通过调用挂起线程pause(),SIGUSR2 恢复线程。

From the man page of pause:

从暂停的手册页:

pause() causes the calling process (or thread) to sleep until a signal is delivered that either terminates the process or causes the invocation of a signal-catching function.

pause() 使调用进程(或线程)休眠,直到传递终止进程或导致调用信号捕获函数的信号。

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>

// Since I have only 2 threads so using two variables, 
// array of bools will be more useful for `n` number of threads.
static int is_th1_ready = 0;
static int is_th2_ready = 0;

static void cb_sig(int signal)
{
        switch(signal) {
        case SIGUSR1:
                pause();
                break;
        case SIGUSR2:
                break;
        }
}

static void *thread_job(void *t_id)
{
        int i = 0;
        struct sigaction act;

        pthread_detach(pthread_self());
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        act.sa_handler = cb_sig;

        if (sigaction(SIGUSR1, &act, NULL) == -1) 
                printf("unable to handle siguser1\n");
        if (sigaction(SIGUSR2, &act, NULL) == -1) 
                printf("unable to handle siguser2\n");

        if (t_id == (void *)1)
            is_th1_ready = 1;
        if (t_id == (void *)2)
            is_th2_ready = 1;

        while (1) {
                printf("thread id: %p, counter: %d\n", t_id, i++);
                sleep(1);
        }

        return NULL;
}

int main()
{
        int terminate = 0;
        int user_input;
        pthread_t thread1, thread2;

        pthread_create(&thread1, NULL, thread_job, (void *)1);
        // Spawned thread2 just to make sure it isn't suspended/paused 
        // when thread1 received SIGUSR1/SIGUSR2 signal
        pthread_create(&thread2, NULL, thread_job, (void *)2);

        while (!is_th1_ready && !is_th2_ready);

        while (!terminate) {
                // to test, I am sensing signals depending on input from STDIN
                printf("0: pause thread1, 1: resume thread1, -1: exit\n");
                scanf("%d", &user_input);

                switch(user_input) {
                case -1: 
                        printf("terminating\n");
                        terminate = 1;
                        break;
                case 0:
                        printf("raising SIGUSR1 to thread1\n");
                        pthread_kill(thread1, SIGUSR1);
                        break;
                case 1:
                        printf("raising SIGUSR2 to thread1\n");
                        pthread_kill(thread1, SIGUSR2);
                        break;
                }
        }

        pthread_kill(thread1, SIGKILL);
        pthread_kill(thread2, SIGKILL);

        return 0;
}