进程间通信失败

时间:2021-03-14 19:09:39
进程AB 共享两个windows 核心句柄 EVENT. hExit 和 Husing;
代码如下

// 进程A 创建命名的 event,并设置husing 为授信,最后等待hexit 事件,退出
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
HANDLE hExitEvent = ::CreateEvent(&sa,false,false,TEXT("_hExitEvent"));
HANDLE husedEvent = ::CreateEvent(&sa,false,false,TEXT("_hUsedEvent"));

STARTUPINFO si;   
ZeroMemory(&si,sizeof(si));   
si.cb=sizeof(STARTUPINFO); 
PROCESS_INFORMATION pi;
if(!CreateProcess(NULL,TEXT("ChildProcess.exe"),NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
cout<<"failed to run chilld process"<<endl;
}
::SetEvent(husedEvent);
cout<<"Reset HUSEDEVENT" <<endl;
Sleep(100);
::WaitForSingleObject(hExitEvent,INFINITE);

system("PAUSE");
return 0;


进程B 

//B等待husing 事件,然后设置 hexit 事件授信,推出.
HANDLE hEvent_exit = ::OpenEvent(NULL,false,TEXT("_hExitEvent"));
HANDLE hTestEvent  = ::OpenEvent(NULL,false,TEXT("_hUsedEvent"));

::WaitForSingleObject(hTestEvent,INFINITE);
cout<<"recive the message from parent!"<<endl;
SetEvent(hEvent_exit);
Sleep(50);

现在问题是,B能收到事件husing,然后设置hexit,退出了,但是进程A 还在哪等待hExit 事件,而且是一直等待。

那个高人回答下为什么呢?

27 个解决方案

#1


有没有其他线程或者进程reset  hEvent_exit

  CEvent::SetEvent
  BOOL SetEvent();
  返回值:如果操作成功,则返回非零值,否则为0。
  说明:
  设置事件的状态为有标记,释放任意等待线程。如果事件是手工的,此事件将保持有标记直到调用 ResetEvent。这种情况下将释放多个线程,如果事件是自动的,此事件将保持有标记,直到一个线程被释放,系统将设置事件的状态为无标记。如果没有线程在等待,则此事件将保持有标记,直到一个线程被释放。

#2


问题解决。 散分了,来人给分,晚上结贴

#3


GX   .

#4


我是进来学习的。

#5


JF...

#6


我来接分

#7


来接分了

#8


顺便说下你的问题所在,解决办法是什么

#9


来接分了

#10


来接分了

#11


咋解决的啊。。。

#12


UP~~~

#13


楼主也不说说是怎么回事哦。。。
让我过下瘾吧。

#14


问题确实被解决了,但是仍然存在困惑,高人可以解答下
1:使用命名句柄方法,A 进程创建 通信句柄时候去掉权限的限制,如下CreateEvent第一个参数为NULL
    HANDLE hExitEvent = ::CreateEvent(NULL,false,false,TEXT("_hExitEvent"));
    HANDLE husedEvent = ::CreateEvent(NULL,false,false,TEXT("_hUsedEvent"));

    STARTUPINFO si;   
    ZeroMemory(&si,sizeof(si));   
    si.cb=sizeof(STARTUPINFO); 
    PROCESS_INFORMATION pi;
    if(!CreateProcess(NULL,TEXT("ChildProcess.exe"),NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
    {
        cout<<"failed to run chilld process"<<endl;
    }
    ::SetEvent(husedEvent);
    cout<<"send message to parent!" <<endl;
    Sleep(100);
    ::WaitForSingleObject(hExitEvent,INFINITE);
cout<<"Answered by  other process!\n";
    system("PAUSE");
    return 0;

进程B 使用createEvent “创建”同样命名的句柄
	HANDLE hExitEvent = ::CreateEvent(NULL,false,false,TEXT("_hExitEvent"));
if(::GetLastError() ==ERROR_ALREADY_EXISTS )
{
cout<<"HANDLE is created by another process\n";
}
    HANDLE husedEvent = ::CreateEvent(NULL,false,false,TEXT("_hUsedEvent"));

    ::WaitForSingleObject(husedEvent,INFINITE);
    cout<<"recive the message from parent!"<<endl;
    SetEvent(hExitEvent);
    Sleep(50);

return 0;


这个时候通信成功了,比较疑惑,如果我使用OPenEvent 打开句柄就不行,getlasterror 提示为0;
以上是我现在使用的解决方案,不过命名换成了不冲突的,是一个初级解决方案。

#15


第2个解决方案比较简单
通过继承句柄来通信的。
我大致说下
CreateEvent()的第一个参数初始化一下。并传入,
然后在进程A中(父进程)创建子进程时候选择可以继承,并且在cmdline 中传入事件的内核地址
进程B中,解析Argv[1],解释成一个地址,赋给一个HANDLE,setEvent 这个handle通知进程A退出

这个方法虽然能通信,但是太失败。。。

#16


设置权限的话,进程B应该打开某些权限吧。

顺便接分。

#17


没考虑用PossthreadMessage ?

#18


引用 16 楼 cattycat 的回复:
设置权限的话,进程B应该打开某些权限吧。

顺便接分。

我OPenEvent设置的是那个sync(线程同步类的)权限。GetLastError 提示 为0 ,这时候就跟我帖子的问题一样了,B退出了,A始终在等待。说明B收到了消息,但是,A没收到?

#19


引用 17 楼 traceless 的回复:
没考虑用PossthreadMessage ?


铅哥,说的高级了。我菜的很。吃饭回来试试。米饭去了先

#20


这个好用,不高级的。用几用就熟悉了,要不要我写段代码来测试。。。

#21


接分了!呵呵

#22


引用 20 楼 traceless 的回复:
这个好用,不高级的。用几用就熟悉了,要不要我写段代码来测试。。。

哈哈,我先试试。我先探探MSDN

#23


那好的,呵呵 

#24


我帮你写了个简单的程序,大致是:

在主进程中创建一个子进程和一个线程,线程里处理消息本进程的消息和子进程返回的消息。

PossThreadMessage, 函数的的最后两个参数可以用作想要传递的数据。

#25


MainProc.cpp

#include <Windows.h>
#include <process.h>

const UINT  MS_OPENFINISHED = WM_USER+8001;
const UINT  MS_RUN = MS_OPENFINISHED + 1;   //子进程的消息
const UINT  MS_RETURN = MS_RUN + 1;  

wchar_t g_wcControl = L'\0';
unsigned int g_dwControlThread = 0 ;

void DealMessage(const MSG &msg);
unsigned int static __stdcall MsgCtrlProc(VOID* param);

int _tmain(int argc, _TCHAR* argv[])
{
PROCESS_INFORMATION   pi;   
STARTUPINFO   si;   
memset(&pi, 0, sizeof(PROCESS_INFORMATION));
memset(&si, 0, sizeof(STARTUPINFO));
wchar_t wszExePath[MAX_PATH] = L"F:\\CPPtest\\sdta\\Debug\\ChildProc.exe";  //子进程路径
if(FALSE == CreateProcess(wszExePath, NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
{
return 0;
}
_beginthreadex(NULL, 0, MsgCtrlProc, NULL, 0, &g_dwControlThread);  //创建线程

while (1)
{
wscanf(L"%c", &g_wcControl);   //线程中不能有printf之类的函数,所以在进程中处理
fflush(stdin);
Sleep(100);
if (g_wcControl >= L'a' && g_wcControl <= L'z')
{
::PostThreadMessage(g_dwControlThread, MS_OPENFINISHED, g_wcControl, 0);  //向本进程的线程发送消息
}
else if (g_wcControl >= L'0' && g_wcControl <= L'9')
{
::PostThreadMessage(pi.dwThreadId, MS_RUN, (WPARAM)g_dwControlThread, 0);  //向子进程发送消息
}
}
return 0;
}

unsigned int static __stdcall MsgCtrlProc(VOID* param)
{
BOOL bRet = TRUE;
MSG msg;
while ((bRet = ::GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
continue;
}
else
{
DealMessage(msg);
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}


void DealMessage(const MSG &msg)
{
switch (msg.message)
{
case MS_OPENFINISHED:
{
::MessageBox(NULL, L"控制主进程", L"控制主进程", MB_OK);
}
break;
case MS_RETURN:
{
::MessageBox(NULL, L"Return", L"Return", MB_OK);  //子进程发回的消息
}
}
}




ChildProc.cpp


#include <Windows.h>
#include <process.h>

UINT g_dwControlThread = 0 ;
UINT g_dwMainThread = 0;

const UINT  MS_OPENFINISHED = WM_USER+8001;
const UINT  MS_RUN = MS_OPENFINISHED + 1;
const UINT  MS_RETURN = MS_RUN + 1;

int _tmain(int argc, _TCHAR* argv[])
{
g_dwMainThread = ::GetCurrentThreadId();  //在MainProc那个主进程中用这个获得线程也行,用_beginthreadex是为了程序好控制
    ::MessageBox(NULL, L"受控进程22222", L"受控进程22222", MB_OK);  //测试用
BOOL bRet = TRUE;
MSG msg;
while ((bRet = ::GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
continue;
}
else
{
switch (msg.message)
{
case MS_RUN:
{
::MessageBox(NULL, L"受控进程", L"受控进程", MB_OK);
::PostThreadMessage((DWORD)msg.wParam, MS_RETURN, 0, 0);//接收到主进程的消息,并向主进程发送消息
}
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}

#26


   windows核心编程里面好象有讲的。

#27


为了得分,我不得不说我们关于进程间通讯(ipc)的一点经验。
第一:使用socket通讯,效率高,实用范围大。
第二:推荐使用ascii码通讯。
第三:服务器数据缓冲的处理,先进先出。
第四:处理粘包。
第五:登陆连接,*下线或者重连机制。
第六:使用线程池处理大量服务并行机制。
第七:。。。。。
第八:。。。。。。

#1


有没有其他线程或者进程reset  hEvent_exit

  CEvent::SetEvent
  BOOL SetEvent();
  返回值:如果操作成功,则返回非零值,否则为0。
  说明:
  设置事件的状态为有标记,释放任意等待线程。如果事件是手工的,此事件将保持有标记直到调用 ResetEvent。这种情况下将释放多个线程,如果事件是自动的,此事件将保持有标记,直到一个线程被释放,系统将设置事件的状态为无标记。如果没有线程在等待,则此事件将保持有标记,直到一个线程被释放。

#2


问题解决。 散分了,来人给分,晚上结贴

#3


GX   .

#4


我是进来学习的。

#5


JF...

#6


我来接分

#7


来接分了

#8


顺便说下你的问题所在,解决办法是什么

#9


来接分了

#10


来接分了

#11


咋解决的啊。。。

#12


UP~~~

#13


楼主也不说说是怎么回事哦。。。
让我过下瘾吧。

#14


问题确实被解决了,但是仍然存在困惑,高人可以解答下
1:使用命名句柄方法,A 进程创建 通信句柄时候去掉权限的限制,如下CreateEvent第一个参数为NULL
    HANDLE hExitEvent = ::CreateEvent(NULL,false,false,TEXT("_hExitEvent"));
    HANDLE husedEvent = ::CreateEvent(NULL,false,false,TEXT("_hUsedEvent"));

    STARTUPINFO si;   
    ZeroMemory(&si,sizeof(si));   
    si.cb=sizeof(STARTUPINFO); 
    PROCESS_INFORMATION pi;
    if(!CreateProcess(NULL,TEXT("ChildProcess.exe"),NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
    {
        cout<<"failed to run chilld process"<<endl;
    }
    ::SetEvent(husedEvent);
    cout<<"send message to parent!" <<endl;
    Sleep(100);
    ::WaitForSingleObject(hExitEvent,INFINITE);
cout<<"Answered by  other process!\n";
    system("PAUSE");
    return 0;

进程B 使用createEvent “创建”同样命名的句柄
	HANDLE hExitEvent = ::CreateEvent(NULL,false,false,TEXT("_hExitEvent"));
if(::GetLastError() ==ERROR_ALREADY_EXISTS )
{
cout<<"HANDLE is created by another process\n";
}
    HANDLE husedEvent = ::CreateEvent(NULL,false,false,TEXT("_hUsedEvent"));

    ::WaitForSingleObject(husedEvent,INFINITE);
    cout<<"recive the message from parent!"<<endl;
    SetEvent(hExitEvent);
    Sleep(50);

return 0;


这个时候通信成功了,比较疑惑,如果我使用OPenEvent 打开句柄就不行,getlasterror 提示为0;
以上是我现在使用的解决方案,不过命名换成了不冲突的,是一个初级解决方案。

#15


第2个解决方案比较简单
通过继承句柄来通信的。
我大致说下
CreateEvent()的第一个参数初始化一下。并传入,
然后在进程A中(父进程)创建子进程时候选择可以继承,并且在cmdline 中传入事件的内核地址
进程B中,解析Argv[1],解释成一个地址,赋给一个HANDLE,setEvent 这个handle通知进程A退出

这个方法虽然能通信,但是太失败。。。

#16


设置权限的话,进程B应该打开某些权限吧。

顺便接分。

#17


没考虑用PossthreadMessage ?

#18


引用 16 楼 cattycat 的回复:
设置权限的话,进程B应该打开某些权限吧。

顺便接分。

我OPenEvent设置的是那个sync(线程同步类的)权限。GetLastError 提示 为0 ,这时候就跟我帖子的问题一样了,B退出了,A始终在等待。说明B收到了消息,但是,A没收到?

#19


引用 17 楼 traceless 的回复:
没考虑用PossthreadMessage ?


铅哥,说的高级了。我菜的很。吃饭回来试试。米饭去了先

#20


这个好用,不高级的。用几用就熟悉了,要不要我写段代码来测试。。。

#21


接分了!呵呵

#22


引用 20 楼 traceless 的回复:
这个好用,不高级的。用几用就熟悉了,要不要我写段代码来测试。。。

哈哈,我先试试。我先探探MSDN

#23


那好的,呵呵 

#24


我帮你写了个简单的程序,大致是:

在主进程中创建一个子进程和一个线程,线程里处理消息本进程的消息和子进程返回的消息。

PossThreadMessage, 函数的的最后两个参数可以用作想要传递的数据。

#25


MainProc.cpp

#include <Windows.h>
#include <process.h>

const UINT  MS_OPENFINISHED = WM_USER+8001;
const UINT  MS_RUN = MS_OPENFINISHED + 1;   //子进程的消息
const UINT  MS_RETURN = MS_RUN + 1;  

wchar_t g_wcControl = L'\0';
unsigned int g_dwControlThread = 0 ;

void DealMessage(const MSG &msg);
unsigned int static __stdcall MsgCtrlProc(VOID* param);

int _tmain(int argc, _TCHAR* argv[])
{
PROCESS_INFORMATION   pi;   
STARTUPINFO   si;   
memset(&pi, 0, sizeof(PROCESS_INFORMATION));
memset(&si, 0, sizeof(STARTUPINFO));
wchar_t wszExePath[MAX_PATH] = L"F:\\CPPtest\\sdta\\Debug\\ChildProc.exe";  //子进程路径
if(FALSE == CreateProcess(wszExePath, NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
{
return 0;
}
_beginthreadex(NULL, 0, MsgCtrlProc, NULL, 0, &g_dwControlThread);  //创建线程

while (1)
{
wscanf(L"%c", &g_wcControl);   //线程中不能有printf之类的函数,所以在进程中处理
fflush(stdin);
Sleep(100);
if (g_wcControl >= L'a' && g_wcControl <= L'z')
{
::PostThreadMessage(g_dwControlThread, MS_OPENFINISHED, g_wcControl, 0);  //向本进程的线程发送消息
}
else if (g_wcControl >= L'0' && g_wcControl <= L'9')
{
::PostThreadMessage(pi.dwThreadId, MS_RUN, (WPARAM)g_dwControlThread, 0);  //向子进程发送消息
}
}
return 0;
}

unsigned int static __stdcall MsgCtrlProc(VOID* param)
{
BOOL bRet = TRUE;
MSG msg;
while ((bRet = ::GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
continue;
}
else
{
DealMessage(msg);
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}


void DealMessage(const MSG &msg)
{
switch (msg.message)
{
case MS_OPENFINISHED:
{
::MessageBox(NULL, L"控制主进程", L"控制主进程", MB_OK);
}
break;
case MS_RETURN:
{
::MessageBox(NULL, L"Return", L"Return", MB_OK);  //子进程发回的消息
}
}
}




ChildProc.cpp


#include <Windows.h>
#include <process.h>

UINT g_dwControlThread = 0 ;
UINT g_dwMainThread = 0;

const UINT  MS_OPENFINISHED = WM_USER+8001;
const UINT  MS_RUN = MS_OPENFINISHED + 1;
const UINT  MS_RETURN = MS_RUN + 1;

int _tmain(int argc, _TCHAR* argv[])
{
g_dwMainThread = ::GetCurrentThreadId();  //在MainProc那个主进程中用这个获得线程也行,用_beginthreadex是为了程序好控制
    ::MessageBox(NULL, L"受控进程22222", L"受控进程22222", MB_OK);  //测试用
BOOL bRet = TRUE;
MSG msg;
while ((bRet = ::GetMessage(&msg, NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
continue;
}
else
{
switch (msg.message)
{
case MS_RUN:
{
::MessageBox(NULL, L"受控进程", L"受控进程", MB_OK);
::PostThreadMessage((DWORD)msg.wParam, MS_RETURN, 0, 0);//接收到主进程的消息,并向主进程发送消息
}
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}

#26


   windows核心编程里面好象有讲的。

#27


为了得分,我不得不说我们关于进程间通讯(ipc)的一点经验。
第一:使用socket通讯,效率高,实用范围大。
第二:推荐使用ascii码通讯。
第三:服务器数据缓冲的处理,先进先出。
第四:处理粘包。
第五:登陆连接,*下线或者重连机制。
第六:使用线程池处理大量服务并行机制。
第七:。。。。。
第八:。。。。。。