CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 22
  1. #1
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Notify client apps of a one-time event from a system service

    I was able to come up with a solution to the following problem but it turned out quite bulky, so I was wondering if there's a better approach to this?

    I have a local service application along with running client applications (that run on each logged on user session account.) The service application needs to notify all client applications to perform a one time operation (say, read data from the registry and process it.) How do you implement this mechanism of notifying all client apps of a one-time event?

  2. #2
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Notify client apps of a one-time event from a system service

    SetEvent on global named event.
    Or mailslot sometimes.
    Last edited by Igor Vartanov; April 18th, 2012 at 06:15 AM.
    Best regards,
    Igor

  3. #3
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Notify client apps of a one-time event from a system service

    If you go the registry route, you'll need to treat it as a multithreaded shared resource.

    As such you will have to protect it so only one thread can access it at a time (or use a readerwriter lock).

  4. #4
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Notify client apps of a one-time event from a system service

    Thank you, guys. I never used mail slots. Registry seems to lack speed and "security" -- anyone can see the data. But, Igor, do you have any more details on how you'd do it with global events?

  5. #5
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    Re: Notify client apps of a one-time event from a system service

    Have a look at CreateEvent function, description of
    pName [in, optional]
    parameter
    Victor Nijegorodov

  6. #6
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: Notify client apps of a one-time event from a system service

    Quote Originally Posted by ahmd View Post
    Thank you, guys. I never used mail slots. Registry seems to lack speed and "security" -- anyone can see the data. But, Igor, do you have any more details on how you'd do it with global events?
    Do you know how to check if an event has been set?

  7. #7
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Notify client apps of a one-time event from a system service

    I know how to do all that with events. What I don't know is how to make a one-time event notification of client apps?

  8. #8
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Notify client apps of a one-time event from a system service

    But, Igor, do you have any more details on how you'd do it with global events?
    Usually I do it like this: A dedicated thread for listening multiple events. External or internal, it doesn't matter and depends on design. At least it's always an internal app shutdown event and some external event(s). Application creates events and passes those to the thread. The thread just waits in WaitForMultipleObjects. On every particular event it notifies main thread somehow, posting dedicated message in my case. That's it, nothing special.

    And your service merely needs to create/open the named event object and signal it at proper time.
    Best regards,
    Igor

  9. #9
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Notify client apps of a one-time event from a system service

    Igor, I'm still not entirely following you. Let me give you an example.

    Say, the service app collected some data in a global storage and wants to notify all client apps to process it. So we do the following:

    - The service sets the global named event to signaled state.

    - The client app has a worker thread that checks for that global event to be signaled, say using WaitForSingleObject API and then if that event is signaled does its processing.

    But there are two main issues with the approach above:

    1. Once a worker thread in the client app detects that the global event is signaled and does its processing, what shall it do next? It can't go back into a waiting state again because the event is still signaled, which will put it into a loop of doing the processing over and over again. If I introduce a preset delay, some rapidly fired events could be missed.

    2. Of course, one can fix the issue above by creating a global event as auto-reset, or reset it in the client right after its signaled state detection, but that opens another can or worms -- what if there's more than one client app? They will enter the race condition -- since one can reset the global event before another one can notice its signaled state.

    That's what I'm trying to address.
    Last edited by ahmd; April 18th, 2012 at 09:00 PM.

  10. #10
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Notify client apps of a one-time event from a system service

    Quote Originally Posted by ahmd View Post
    Igor, I'm still not entirely following you. Let me give you an example.

    Say, the service app collected some data in a global storage and wants to notify all client apps to process it. So we do the following:

    - The service sets the global named event to signaled state.

    - The client app has a worker thread that checks for that global event to be signaled, say using WaitForSingleObject API and then if that event is signaled does its processing.

    But there are two main issues with the approach above:

    1. Once a worker thread in the client app detects that the global event is signaled and does its processing, what shall it do next? It can't go back into a waiting state again because the event is still signaled, which will put it into a loop of doing the processing over and over again. If I introduce a preset delay, some rapidly fired events could be missed.
    Typically this can be solved by special data organization, like having a queue or list of tasks to be done, and firing event just indicates that the queue is not empty.

    But in case that every event must be properly delivered to every client, some stream based data exchange is preferable. Mailslots, named pipes, sockets, whatever.

    2. Of course, one can fix the issue above by creating a global event as auto-reset, or reset it in the client right after its signaled state detection, but that opens another can or worms -- what if there's more than one client app? They will enter the race condition -- since one can reset the global event before another one can notice its signaled state.
    No, auto-reset event is not an option in multi-client environment with reliable message delivery.

    EDIT: I made a sample for you to play with. You can run a few clients and see how it goes.
    Attached Files Attached Files
    Last edited by Igor Vartanov; April 18th, 2012 at 10:24 PM.
    Best regards,
    Igor

  11. #11
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Notify client apps of a one-time event from a system service

    Quote Originally Posted by Igor Vartanov View Post
    EDIT: I made a sample for you to play with. You can run a few clients and see how it goes.
    Much appreciated, Igor. I also like your coding style, and how you culled out all the MFC fluff to make it very readable. This line is my favorite though:
    Code:
    CloseHandle(CreateThread(NULL, 0, Listener, *this, 0, &threadId));
    I'm always baffled about what to do with those handles returned by CreateThread. I usually keep them open until the thread closes. (I was originally erroneously thinking though that closing a thread handle will terminate it -- and I'm sure many beginners would make such assumption as well.)

    It is also so rare in MS community these days to see people code in clean WinAPI. So in your face, C#

    I have to disagree with your handling of that global event though. I'm talking about this part in the Signal() method of the service:
    Code:
    SetEvent(hEvent);
    Sleep(10);
    ResetEvent(hEvent);
    What if one of the clients is busy within those 10 ms, or the system it runs on is too slow to handle it in time?

    Let me share the way I handled it and I want to hear what you think about my approach? It's a little bit more bulky, though. And, sorry I don't have time to make a code sample. Instead, I'll show it in pseudo-code:

    Client
    ======

    - Create a global named auto-reset event, with a special unique/repeatable name. This event should exist throughout the life-cycle of the client. In my case there could be only one client per logged on user session, so use that:
    Code:
    //Get current session ID
    DWORD dwSessID;
    ProcessIdToSessionId(GetCurrentProcessId(), &dwSessID);
    
    CString strEventName;
    strEventName.Format(_T("Global\\MyEventName%d"), dwSessID);
    
    //In my "real" example, I set up a security descriptor "For everyone" but
    //as I think about it, the event should be accessible from a service with
    //a default descriptor anyway -- otherwise use it from Igor's example
    HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, strEventName);
    - Wait on a newly created event from a worker thread:
    Code:
    for(;bLoop;)
    {
    	//Just a usual stuff...
    	DWORD dwR = WaitForSingleObject(hEvent, INFINITE);
    	if(dwR == WAIT_OBJECT_0)
    	{
    		//Do event processing -- no Sleep()'ing needed
    	}
    	else
    	{
    		//Error
    	}
    
    	//...
    }
    Service
    ========

    - When we need to notify all clients we enumerate all logged on user sessions using WTSEnumerateSessions() API, looking for session IDs with the WTSActive connection state.

    - And then open global events with names that we've created for each client and signal them:
    Code:
    //Error handling is omitted
    for(int i = 0; i < _count(dwLoggedOnUserSessions); i++)
    {
    	DWORD dwUserSessID = dwLoggedOnUserSessions[i];
    
    	CString strEventName;
    	strEventName.Format(_T("Global\\MyEventName%d"), dwUserSessID);
    
    	HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, strEventName);
    	SetEvent(hEvent);
    	CloseHandle(hEvent);
    }
    Last edited by ahmd; April 19th, 2012 at 01:40 PM.

  12. #12
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Notify client apps of a one-time event from a system service

    Again, as I said it depends on whole design, and my sample was just a one version among few possible ones.

    In fact, it was just a demonstration that one event been fired could be caught in unlimited number of clients. As to what you said about 10ms sleep, maybe I never had a project with such a critical requirements. All my stuff I typically deal with surely can wait even for longer intervals without any noticeable impact on workflow.

    And yes, the approach with event names "uniquealized" by some client traits I really used before a couple of times in the past.
    Best regards,
    Igor

  13. #13
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Notify client apps of a one-time event from a system service

    What if one of the clients is busy within those 10 ms, or the system it runs on is too slow to handle it in time?
    One more thing to say. Client listener must do no lengthy processing on the event it catches. In my sample it just posts a message and returns after some short delay needed to suppress "chattering" on the signal. Anyway, in case in a real project this sort of delay is unacceptable, this point must be just carefully designed in accordance with real project requirements.
    Best regards,
    Igor

  14. #14
    Join Date
    Feb 2009
    Location
    Portland, OR
    Posts
    1,488

    Re: Notify client apps of a one-time event from a system service

    As a side note, what's your opinion. Why doesn't MS introduce an easier method of communication between processes? Something alike messages but for processes (or even threads) instead of windows. I know that there're named pipes, memory mapped files, etc. but anyone who dealt with those knows how complex and error prone coding them may be (I don't even mention debugging a system service and a client app at the same time.)

    Anyway, wouldn't it be cool to have an API alike SendMessageToProcess() that can take a memory array as a parameter and then on the other end have something akin to GetProcessMessage that will receive it (again, pretty much like a message pump works now, but with an addition of a variable size byte array as a parameter.) Also something that runs without the use of higher level layers like COM, etc. to make it also kernel-level fast.
    Last edited by ahmd; April 19th, 2012 at 08:14 PM.

  15. #15
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Notify client apps of a one-time event from a system service

    I have no answer, sorry. What you describe surely could be implemented in a form of a library, and I don't sure this worth to be a part of OS. For me it was always enough to have existing Windows stuff at disposal. I use IPC not that frequent to complain about Windows lacking something. But when I have to, it typically needs something simple (well, simple to my experience ) I can easily handle with. Maybe this is because the architecture design is typically mine too so I have nobody to blame on but me.
    Best regards,
    Igor

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured