【问题标题】:Signal handler getting called in wrong thread在错误的线程中调用信号处理程序
【发布时间】:2015-07-16 17:49:01
【问题描述】:

我想知道是否可以中断主线程并要求它执行一些回调。完成回调后,主线程应该继续它正在做的事情。

例如,我们有 2 个线程 t1 和 m1(主线程)。 t1 将中断 m1(主线程)并要求它调用带有一些参数的函数。 m1(主线程)将停止执行它之前正在执行的操作并开始执行该函数。完成该功能后,它会恢复到之前的状态。

我想复制硬件中断的作用。我有一个从文件中读取数据的线程。然后它应该要求主线程调用一个函数。主线程将做一些事情。它应该停止这样做并开始执行该功能。完成后,主线程应该继续它正在做的事情

我使用信号编写了以下代码

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

static void catch_function(int signo) {
    int id = GetCurrentThreadId();
    printf("\nThread ID is %d",id);
    signal(SIGINT, catch_function);
}


DWORD WINAPI MyThreadFunction( LPVOID lpParam ) 
{
    int id = GetCurrentThreadId();
    printf("\nChild Thread ID is %d",id);
    while(1)
    {
        Sleep(50);
        if (raise(SIGINT) != 0) {
            fputs("Error raising the signal.\n", stderr);
            return EXIT_FAILURE;
        }
    }
    return 0;
}


int main(void) {

    int id = GetCurrentThreadId();
    printf("\nMain Thread ID is %d",id);
    if (signal(SIGINT, catch_function) == SIG_ERR) {
        fputs("An error occurred while setting a signal handler.\n", stderr);
        return EXIT_FAILURE;
    }

    HANDLE thread;
    DWORD  threadId;
    thread = CreateThread(NULL, 0, &MyThreadFunction, NULL, 0, &threadId);
    if(!thread)
    {
        printf("CreateThread() failed");
    }

    while(1)
    {
        Sleep(50);
    }
    return 0;
}

代码的输出是

Main Thread ID is 6124 
Child Thread ID is 7854
Thread ID is       7854
Thread ID is       7854

所以我的问题是不应该在主线程中调用信号处理程序吗?我希望主线程调用处理函数而不是引发信号的线程? 请让我知道实现这一目标的正确方法是什么。

PS。我必须为 windows 和 linux 都这样做。

【问题讨论】:

  • 信号量互斥条件变量比向进程发出信号更好

标签: c multithreading signals interrupt


【解决方案1】:

我只能提供来自 Linux 方面的建议,但正如你所说,当时这也很有趣......

...raise 执行以下操作(来自手册页):

The  raise()  function sends a signal to the calling process or thread.

所以在多线程程序中,调用 raise 的线程将获得信号。

在 Linux 上,对于线程,您可能会使用 pthreads,在这种情况下您有 pthread_kill,这会将特定信号发送到特定线程。您需要在主线程中使用pthread_self 来获取线程ID,然后将其传递给工作线程。然后工作线程可以直接向主线程发送信号。

我怀疑你需要为 Windows 找到类似的东西,但这不是我所知道的。

【讨论】:

    【解决方案2】:

    唯一可以中断线程的是它自己或任务调度程序。 如果您要阻止其他人,您将需要直接访问计时器硬件。

    你可以按照 Ed Heal 所说的去做。使用条件变量和信号量。我的建议是建立一个链表,甚至只是一个数组来存储要做什么以及应该由谁来做。

    查看 Windows 在“事件驱动的 UI”中如何向程序发送消息。 一个 MSG 结构体被提供给应用程序,其中包含一些整数,如消息代码、WPARAM 和 LPARAM。

    定义您自己的结构并使用它向每个线程发送消息(某种形式的进程间通信)。而且,这很重要,将计时器设置为回调函数或保留您的 Sleep(50)(或更多),以免无缘无故地“打扰”您的处理器。

    希望这会有所帮助,对糟糕的英语感到抱歉。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多