如何通过进程发送事件信号-C

如何通过进程发送事件信号-C,c,winapi,events,multithreading,process,C,Winapi,Events,Multithreading,Process,我有一个由两个窗口组成的应用程序,一个窗口与另一个窗口通信,并向它发送一个包含两个整数的结构(在本例中是两个骰子) 我将在以下情况下使用事件: 进程a向进程b发送数据,进程b显示数据 流程a关闭,反过来关闭流程b 进程b关闭进程a,反过来关闭进程a 我注意到,如果第二个进程一直在等待第一个进程发送数据,那么程序将只是坐在那里等待,这就是在每个进程上实现线程的想法,我已经开始实现了 我遇到的问题是,我对线程和事件没有太多经验,因此我不确定实际实现我想要做的事情的最佳方法 我试图弄清楚另一个进程

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

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

  • 进程a向进程b发送数据,进程b显示数据
  • 流程a关闭,反过来关闭流程b
  • 进程b关闭进程a,反过来关闭进程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);
            }
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);
            }
case WM_DESTROY:
        {
            SetEvent(hConsumerCloseEvent);
            PostQuitMessage(0);
            break;
        }
我只能对事件使用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);
            }
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);
            }
case WM_DESTROY:
        {
            SetEvent(hConsumerCloseEvent);
            PostQuitMessage(0);
            break;
        }
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中):

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);
            }
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);
            }
case WM_DESTROY:
        {
            SetEvent(hConsumerCloseEvent);
            PostQuitMessage(0);
            break;
        }
将事件设置为B关闭时发出信号:

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);
            }
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);
            }
case WM_DESTROY:
        {
            SetEvent(hConsumerCloseEvent);
            PostQuitMessage(0);
            break;
        }
正如您看到的,当事件发出信号时,应用程序A被设置为关闭。当我运行应用程序并关闭进程B时,进程A不会注意到已更改的信号,也不会关闭

编辑2:

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);
            }
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);
            }
case WM_DESTROY:
        {
            SetEvent(hConsumerCloseEvent);
            PostQuitMessage(0);
            break;
        }
在使用GetLastError()之后;我能够识别OpenEvent的句柄为NULL,给出的错误为

错误\u未找到文件\u \u-2:系统错误 找不到指定的文件


如果我创建和读取事件的方法不正确,我已确保包含全局\前缀。

听起来您可能想使用
。您可以使用信号量来表示可供进程b处理的数据项的数量。当数据项可用时,将其初始化为0计数,并用
递增。然后在进程b中调用
,或者调用它的一个bretheren,只有当信号量计数大于0时才会返回,此时计数会递减


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

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

过程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);
  }
}

不幸的是,我仅限于使用CreateEvent/SetEvent等。。方法集,很抱歉在问题中没有提及。我不明白为什么您提供的每个示例都有重复的事件集,以及每个进程如何判断另一个进程已更改状态?。出于某种原因,即使我将事件设置为false,程序仍然会立即看到它发出的信号,这是没有意义的。它实际上是由两个事件组成的一组。请注意,名称是相同的,运行的第一个进程将创建它们,第二个进程将获得预先存在的事件的句柄。我建议在这两种情况下都使用CreateEvent(与一个进程中的CreateEvent和另一个进程中的OpenEvent相比)的原因是,这意味着先启动哪个进程并不重要。事件被共享的事实就是你如何共享状态。我不知道为什么你会像往常一样看到这些事件。你能简单解释一下吗?MSDN文档只显示如何在一个过程中完成,而不是在两个过程之间完成,因此很难理解。您不理解的方面是什么?我添加了一些附加信息,以帮助解释我的错误所在。