signal阻塞, 挂起

本文通过三个实例详细介绍了Linux环境下信号处理的几种方式:信号的阻塞与恢复、信号挂起及取出挂起信号、使用pause和sigsuspend暂停进程直至接收到信号。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

signal阻塞, 挂起, 恢复

例1: 信号阻塞及阻塞解除

mysigprocmask.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>

void handler(int signum)
{
    static int count = 0;
    count++;
    printf("hello i'm signal %d,count = %d\n",signum,count);
}

void child_process(int signum)
{
    puts("i'm process my child");
    wait(NULL);
}

int main(int argc, char *argv[])
{
    int i;
    printf("pid = %d\n",getpid());

    for(i = 1;i <= 64;i++)
    {
        if(SIG_ERR == signal(i,handler))
        {
            printf("error = %d\n",i);
        }
    }

    sigset_t now, old;
    sigfillset(&now);
    sigprocmask(SIG_SETMASK,&now,&old);

    puts("all signal is blocked...");
    puts("please enter any key to unblocked...");
    getchar();

    sigprocmask(SIG_SETMASK,&old,NULL);

    getchar();

    return 0;
}

编译链接执行, 结果如下:

解除阻塞前, 多次改变窗口大小, 多次按下"ctrl+c", 按下回车后, 28和2各打印输出一次. 再次改变窗口大小, 或按下ctrl+c, 每次都有打印输出.

 

例2: 信号挂起, 取出挂起的信号

mysigpending.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>

#undef SIGINT
#define SIGINT 60

void handler(int signum)
{
    static int count = 0;
    count++;
    printf("hello i'm signal %d,count = %d\n", signum, count);
}


int main(int argc, char *argv[])
{
    int i;
    sigset_t new,old,pend;

    printf("pid = %d\n",getpid());
    signal(SIGINT,handler);
    puts("SIGINT is set...");
    getchar();

    sigemptyset(&new);
    sigaddset(&new,SIGINT);
    sigprocmask(SIG_BLOCK,&new,&old);
    puts("SIGINT is blocked...");
    getchar();

    sigpending(&new);
    if(sigismember(&new,SIGINT))
        puts("ISGINT is in pending queue...");
    else
        puts("SIGINT is not int pending queue..");
    sigprocmask(SIG_SETMASK,&old,NULL);
    puts("SIGINT is unblocked...");
    getchar();

    return 0;
}

编译链接执行后, 结果如下:

另一终端运行如下命令:

运行起来后,

 a. 在另一个终端运行"kill -60 9581"向其发信号, 每次都有响应信号. 

 b. 通过sigemptyset()/sigaddset()/sigprocmask()阻塞60信号. 此时在另一个终端运行"kill -60 9581"向其发信号, 没有响应. 

 c. sigpending()/sigismember()取得挂起的信号集合

 d. sigprocmask()解除60信号阻塞.  立即有打印输出.

 

例3: 暂停进程, 直到收到信号

mysigsuspend.c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>

void handler(int signum)
{
    printf("signal: %d\n");
}

int main(int argc, char *argv[])
{
    printf("pid = %d\n",getpid());    
    
    signal(28,handler);

    sigset_t new,old;
    sigfillset(&new);
    sigprocmask(SIG_SETMASK,&new,&old);
    puts("BLOCKED..");

    sigsuspend(&old);
    printf("[%s - %d]info \n", __func__, __LINE__);
#if 0
    sigprocmask(SIG_SETMASK,&old,NULL);
    pause();

#endif
    return 0;
}

编译链接执行, 结果输出如下:

运行后程序暂停, 直到窗口发生变化(产生SIGWINCH信号), 或从其它终端向其发信号(如"kill -61 10672")时, 程序才退出.

转载于:https://www.cnblogs.com/zhanglong71/p/5100545.html

<think>我们正在讨论如何使用GDB调试多线程程序,特别是如何暂停特定线程。根据引用内容,我们可以知道GDB有多种模式来控制线程的执行,其中scheduler-locking模式可以帮助我们锁定其他线程,只允许特定线程运行。但用户的需求是暂停特定线程,而不是只让特定线程运行。在引用[4]中提到,可以使用`callraise(kernel-thread-id,signo)`或`callpthread_kill(pthread-thread-id,signo)`向特定线程发送信号。我们可以发送一个暂停信号(如SIGSTOP)来挂起特定线程。然而,在GDB中,我们通常使用`thread`命令切换到特定线程,然后使用`signalSIGSTOP`命令向该线程发送SIGSTOP信号。注意:直接发送SIGSTOP可能会使线程暂停,但GDB可能不会立即显示该线程的状态变化。另一种方法是使用GDB的`interrupt`命令,但`interrupt`通常用于中断整个程序(即所有线程)。不过,我们可以先切换到目标线程,然后使用`interrupt`命令,但这样会中断整个进程?所以可能不是我们想要的。实际上,在GDB中暂停特定线程的常见做法是:1.设置scheduler-locking为on,这样只有当前线程会运行,其他线程被暂停。但这并不是暂停特定线程,而是暂停除当前线程外的所有线程。2.我们想要的是只暂停某个线程,而其他线程继续运行。根据引用[4],我们可以通过调用pthread_kill向特定线程发送SIGSTOP信号。步骤大致如下:-首先,获取要暂停的线程的pthread_t(即线程ID)。在GDB中,我们可以通过`infothreads`查看线程信息,但显示的线程ID是GDB内部编号,不是pthread_t。我们需要知道目标线程的pthread_t值。-在程序中,我们可以通过变量获取线程ID,但如果没有暴露给调试者,可能比较困难。另一种方法是使用GDB7.0以上版本支持的`threadapply<thread-id>signalSIGSTOP`命令,它可以直接对指定线程发送信号。具体步骤:1.启动GDB,并运行多线程程序。2.使用`infothreads`查看当前线程列表,记录要暂停的线程的GDB内部编号(如2,3等)。3.使用`threadapply<thread-id>signalSIGSTOP`命令,例如:`threadapply2signalSIGSTOP`,这将向线程2发送SIGSTOP信号,从而暂停该线程。注意:发送SIGSTOP信号后,该线程将停止执行,直到收到SIGCONT信号。另外,也可以使用`thread<thread-id>`切换到目标线程,然后使用`signalSIGSTOP`命令(注意:在GDB中,`signal`命令用于向当前线程发送信号)。因此,暂停特定线程(GDB内部编号为2的线程)的命令序列可以是:(gdb)thread2#切换到线程2(gdb)signalSIGSTOP或者,不切换线程直接发送信号:(gdb)threadapply2signalSIGSTOP恢复该线程可以使用:(gdb)threadapply2signalSIGCONT但是,需要注意的是,使用SIGSTOP暂停线程是操作系统级别的,而GDB本身也有暂停线程的机制(比如断点)。这里的方法是通过发送信号强制线程暂停。另外,引用[3]中提到了`scheduler-locking`模式,但这种模式是控制当当前线程运行时,其他线程是否同时运行。它并不能单独暂停某一个线程。因此,针对用户的需求,推荐使用`threadapply<thread-id>signalSIGSTOP`来暂停特定线程。注意:在使用这种方法时,要确保线程能够安全地暂停,避免在持有锁等关键资源时暂停,否则可能导致死锁。总结步骤:1.在GDB中运行程序(例如:`run`),让程序运行起来。2.当需要暂停特定线程时,使用`infothreads`查看线程信息,确定目标线程的GDB编号。3.使用`threadapply<目标线程编号>signalSIGSTOP`暂停该线程。4.如果需要恢复,使用`threadapply<目标线程编号>signalSIGCONT`。另外,在GDB中,也可以使用`interrupt`命令,但`interrupt`会暂停整个进程(所有线程),所以不适用于只暂停单个线程。因此,回答如下:</think>### 在 GDB 中暂停特定线程的方法 在调试多线程程序时,暂停特定线程需结合 GDB 的线程控制命令和信号机制。以下是具体操作步骤: #### 方法 1:直接发送暂停信号(推荐) 1. **查看线程列表** 首先获取目标线程的 GDB 内部 ID: ```bash (gdb) info threads Id Target Id Frame 1 Thread 0x7fff (LWP 123) "main" 2 Thread 0x5555 (LWP 456) "worker" <-- 目标线程 ``` 2. **向特定线程发送 SIGSTOP** 使用 `thread apply` 命令直接发送暂停信号: ```bash (gdb) thread apply 2 signal SIGSTOP ``` - `2` 是目标线程的 GDB ID - 此命令仅暂停线程 2,其他线程继续运行[^4] 3. **恢复线程** 发送 SIGCONT 信号恢复运行: ```bash (gdb) thread apply 2 signal SIGCONT ``` #### 方法 2:结合 `scheduler-locking` 模式 1. **锁定其他线程** 启用严格线程锁定模式: ```bash (gdb) set scheduler-locking on ``` - 此时**只有当前线程会运行**,其他线程自动暂停[^3] 2. **切换并控制目标线程** ```bash (gdb) thread 2 # 切换到目标线程 (gdb) next # 仅该线程单步执行 (gdb) set scheduler-locking off # 解除锁定 ``` #### 方法 3:编程式暂停(需代码支持) 在代码中插入调试接口: ```c #include <signal.h> void debug_pause() { raise(SIGSTOP); // 暂停当前线程 } ``` 在 GDB 中调用: ```bash (gdb) thread 2 (gdb) call debug_pause() # 触发暂停 ``` ### 关键注意事项 1. **信号安全性** - 避免在持有锁或关键资源时暂停线程,否则可能导致死锁 - 优先在安全点(如循环开始处)暂停线程 2. **调试模式选择** - 使用 `set non-stop on` 启用非阻塞模式,允许单独控制线程[^2] - 通过 `show scheduler-locking` 查看当前锁定状态 3. **线程 ID 对应关系** - GDB 内部 ID (`info threads` 显示) 与系统线程 ID (LWP) 不同 - 需通过 `thread find <LWP_ID>` 查找对应关系 > **操作示例**: > 暂停 ID 为 3 的线程: > ```bash > (gdb) thread apply 3 signal SIGSTOP > [Thread 3 (LWP 7890) signaled SIGSTOP] > ``` > 此时仅该线程暂停,其他线程继续执行[^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值