C Linux线程挂起/恢复

C Linux线程挂起/恢复,c,linux,multithreading,pthreads,C,Linux,Multithreading,Pthreads,我正在编写一个代码,其中有两个线程并行运行 第一个线程是从第二个线程开始的主线程。 第二个线程只是一个执行空while循环的简单线程 现在我想暂停/暂停创建第二个线程的第一个线程对第二个线程的执行。 过了一段时间,我想从暂停/挂起的位置恢复第二个线程的执行(通过发出一些命令或函数)。据我所知,您不能使用pthreads暂停其他线程。你必须在你的第二个线程中有一些东西来检查它应该暂停的时间,比如使用一个条件变量。这是执行此类操作的标准方法。您可以使用互斥来执行此操作,伪代码为: While (tr

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

第一个线程是从第二个线程开始的主线程。 第二个线程只是一个执行空while循环的简单线程

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

据我所知,您不能使用pthreads暂停其他线程。你必须在你的第二个线程中有一些东西来检查它应该暂停的时间,比如使用一个条件变量。这是执行此类操作的标准方法。

您可以使用互斥来执行此操作,伪代码为:

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 */
}

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

条件变量机制允许线程暂停执行 并放弃处理器,直到某个条件为真。状况 变量必须始终与互斥体关联以避免竞争 由一个准备等待的线程和另一个线程创建的条件 这可能会在第一个线程实际等待之前发出条件信号 结果导致了僵局

更多信息


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


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

不确定您是否喜欢我的答案。但你可以通过这种方式实现

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

当前没有用于暂停或恢复流程执行的系统但您肯定可以创建一个。

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

  • 为第二个进程注册一个信号处理程序
  • 在信号处理器内部,等待信号量
  • 每当您想暂停另一个进程时,只需发送一个信号
    您向其注册了另一个进程。该计划将进入下一阶段 睡眠状态
  • 当您想要恢复该过程时,可以发送不同的信号 再一次。在该信号处理程序中,您将检查信号量是否正确 锁不锁。如果它被锁定,您将释放信号量。所以
    流程2将继续执行

如果你能实现这一点,请分享你的反馈,如果它为你或不工作。谢谢。

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

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

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

在Unix规范中,有一个名为pthread_suspend的线程函数和另一个名为pthread_resume_np的线程函数,但由于某些原因,Linux、FreeBSD、NetBSD等的制造商尚未实现这些函数

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

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

基于JVM将这种信号技术用于垃圾收集器的事实,我认为可以使用信号来正确地完成这项工作,但我也在网上看到了一些文章,其中人们注意到JVM的死锁等等,有时是不可生产的

因此,为了回答这个问题,除非您有一个实现pthread\u suspend\u np的好Unix,否则您无法正确地使用Unix挂起和恢复线程。否则你就会被信号卡住

信号的一个大问题是,你有五个不同的库,它们都链接到同一个程序,并且都试图同时使用相同的信号。为了这个原因
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);
    }
}
#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;
}