【问题标题】:How to send Event signal through Processes - C如何通过进程发送事件信号 - C
【发布时间】:2011-02-11 02:08:04
【问题描述】:

我有一个由两个窗口组成的应用程序,一个窗口与另一个窗口通信并向其发送一个包含两个整数的结构(在本例中为两个骰子)。

我将在以下情况下使用事件:

  • 进程a向进程b发送数据,进程b显示数据
  • 进程a关闭,依次关闭进程b
  • 进程 b 关闭 a,依次关闭进程 a

我注意到,如果第二个进程一直在等待第一个进程发送数据,那么程序将只是等待,这就是在每个进程上实现线程的想法出现的地方,我已经开始实现这一点.

我遇到的问题是我对线程和事件没有太多经验,所以我不确定实际实现我想做的事情的最佳方法。

我正在尝试弄清楚另一个进程如何知道被触发的事件,以便它可以执行它需要执行的任务,我不明白一个独立于另一个进程的进程如何判断状态事件尤其如此,因为它需要在事件改变状态后立即采取行动。

感谢您的帮助

编辑:

我只能对事件使用 Create/Set/Open 方法,抱歉之前没有提及。

此外,我在进程 A 中创建了一个新线程,它允许用户在侦听关闭事件的同时与应用程序交互。

创建话题:

hCreateEventThread = CreateThread(
                NULL,       // lpThreadAttributes (default)
                0,          // dwStackSize (default)
                ThreadFunc, // lpStartAddress
                NULL,       // lpParameter
                0,          // dwCreationFlags
                &hCreateEventThreadID   // lpThreadId (returned by function)
                );

            if(hCreateEventThread != NULL)
            {
                MessageBox(hMainWindow,L"Thread created!",L"Success!",MB_OK);
            }

B 关闭时 A 上的打开事件

    DWORD WINAPI ThreadFunc(LPVOID passedHandle)
    {
        hConsumerCloseEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, TEXT("Global\\ConsumerCloseEvent"));

        while(TRUE)
        {
            dwCloseResult = WaitForSingleObject(hConsumerCloseEvent,INFINITE);

            switch (dwCloseResult) 
            {
                // State of object is signalled
            case WAIT_OBJECT_0: 
                //Consumer has closed, exit program.
                //CloseHandle(hDiceRoll);
                //CloseHandle(hCloseEvent);
                //CloseHandle(hCreateEventThread);
                ExitProcess(1);
                break;
            default: 
                return;
            }
        }
    }

在 b 中创建事件(在 WM_CREATE 中):

hConsumerCloseEvent = CreateEvent( 
                NULL,               // default security attributes
                TRUE,               // manual-reset event
                TRUE,              // initial state is nonsignaled
                TEXT("Global\\ConsumerCloseEvent")  // object name
                );

            if(hConsumerCloseEvent == NULL)
            {
                MessageBox(hMainWindow,L"CreateEvent failed",L"Error",MB_OK);
            }

将事件设置为 B 关闭时发出信号:

case WM_DESTROY:
        {
            SetEvent(hConsumerCloseEvent);
            PostQuitMessage(0);
            break;
        }

正如您所见,当事件发出信号时,应用程序 A 被设置为关闭。当我同时运行应用程序并关闭进程 B 时,进程 A 没有注意到变化的信号并且没有关闭。

编辑 2:

使用 GetLastError() 后;我能够确定 OpenEvent 的句柄为 NULL,给出的错误是

ERROR_FILE_NOT_FOUND - 2 :系统 找不到指定的文件

我创建事件和读取它的方法是否不正确,我确保包含 Global\ 前缀。

【问题讨论】:

    标签: c winapi events multithreading process


    【解决方案1】:

    信号量的好处是它们单独负责同步两个进程之间的队列深度。由于您仅限于使用 Event 对象,因此我建议您使用进程间消息而不是队列,或者如果您愿意,可以使用一个队列。

    流程A

    // In the initialization code
    ...
    hMessageEmptiedEvent = CreateEvent(NULL, FALSE, TRUE, _T("MessageEmptied"));
    hMessageSentEvent = CreateEvent(NULL, FALSE, FALSE, _T("MessageSent"));
    
    // Call this function when you want to send the data to process b
    void sendData(struct diceData data)
    {
      // Make sure any pre-existing message has been processed
      WaitForSingleObject(hMessageEmptiedEvent, INFINITE);
      // Copy the data into the shared buffer
      *(struct diceData *) pBuf = data;
      // Signal the other process that data is ready
      SetEvent(hMessageSentEvnt);
    }
    

    流程 B

    // In the initialization code
    ...
    hMessageEmptiedEvent = CreateEvent(NULL, FALSE, TRUE, _T("MessageEmptied"));
    hMessageSentEvent = CreateEvent(NULL, FALSE, FALSE, _T("MessageSent"));
    
    // Call this function when you want to recieve data from process a
    struct diceData readData()
    {
      struct diceData data;
    
      // Wait for a message to become available
      WaitForSingleObject(hMessageSentEvent, INFINITE);
      // Copy the data from the shared buffer
      data = * (struct diceData *)pBuf;
      // Signal the other process that message has been read.
      SetEvent(hMessageEmptiedEvnt);
    }
    

    如果,正如我猜测的那样,您实际上想要一个长度大于 1 的队列,您现在可以在进程 b 中实现排队逻辑。出于几个原因,您需要在单独的线程中执行此操作。队列逻辑的实现取决于您。根据您的效率需求,它可以是循环数组或链表或???。

    // In process b's initialzation add a thread to do the queueing
    initializeEmptyQueue();
    hQueueingThread = CreateThread(NULL, 0, enqueueLoop, NULL, 0, NULL);
    
    
    DWORD enqueueLoop(LPVOID ignored)
    {
      while (TRUE)
      {
        struct diceData data;
        data = getData();
        enqueueData(data);
      }
    }
    

    【讨论】:

    • 我不明白为什么您提供的每个样本都有重复的事件集,以及每个进程如何判断另一个进程已更改状态?出于某种原因,即使我已将事件设置为 false,程序仍然会立即看到它的信号,这是没有意义的。
    • 它实际上是一组两个事件。请注意,名称是相同的,第一个运行的进程将创建它们,第二个进程将获得预先存在的事件的句柄。我建议在两种情况下都使用 CreateEvent 的原因(与一个进程中的 CreateEvent 和另一个进程中的 OpenEvent 相比)是它应该意味着您首先启动哪个进程并不重要。共享事件的事实是您共享状态的方式。我不知道你为什么会像往常一样看到这些事件。
    • 你能简单解释一下吗? MSDN 文档只倾向于显示如何在一个进程中执行此操作,而不是在两个进程之间,因此很难理解。
    • 有哪些方面你不明白?
    • 我添加了一些额外的信息来帮助解释我哪里出错了。
    【解决方案2】:

    听起来您可能想使用@987654321@。您可以使用信号量来表示可供进程 b 处理的数据项的数量。将其初始化为 0,当数据项可用时,将其递增为 @987654322@。然后在您的进程 b 中调用 @987654323@ 或其兄弟之一,它只会在信号量计数高于 0 时返回,此时计数会递减。

    这不是完整的解决方案,因为您仍然需要处理诸如共享缓冲区已满时该怎么做之类的事情,但这应该可以让您真正开始。

    【讨论】:

    • 不幸的是,我仅限于使用 CreateEvent/SetEvent 等一组方法,抱歉没有在问题中提及。
    猜你喜欢
    • 1970-01-01
    • 2019-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多