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

时间:2010-04-22 13:43:12

标签: c winapi events multithreading process

我有一个由两个窗口组成的应用程序,一个与另一个窗口进行通信,并向它发送一个构成两个整数的结构(在这种情况下是两个掷骰子)。

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

  • 处理向处理b发送数据,处理b显示数据
  • 处理关闭,然后关闭流程b
  • 流程b关闭a,然后关闭流程

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

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

我正在尝试弄清楚其他进程如何知道被触发的事件,以便它可以完成它需要做的任务,我不明白一个与另一个进程分离的进程如何能够分辨出状态是什么特别是当事件发生变化时需要立即采取行动。

感谢您的帮助

修改

我只能使用事件的创建/设置/打开方法,抱歉早些时候没有提到它。

此外,我在流程A中创建了一个新线程,让用户在监听close事件时与应用程序进行交互。

创建主题

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 \前缀。

2 个答案:

答案 0 :(得分:3)

信号量的好处在于他们单独负责同步两个进程之间的队列深度。由于您仅限于使用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);
}

如果,正如我猜测的那样,你实际上想要一个长度超过一的队列,你现在可以在进程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);
  }
}

答案 1 :(得分:2)

听起来您可能想要使用CreateSemaphore。您可以使用信号量来表示可供流程b处理的数据项的数量。将数据项初始化为0,当数据项可用时,将其增加ReleaseSemaphore。然后在你的过程中b调用WaitForSingleObject或其中一个bretheren,它只会在信号量计数大于0时返回,此时计数会减少。

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