What is an event? The simple answer is it is a kernel object. At the fundamental level, it is a data structure in the kernel. In fact, because an event is the simplest kernel object, its structure is the header for all other kernel objects.
This is how you create an event. Crating an event, if successful, returns a handle to the corresponding kernel object. This is how you close an event. You close the handle to it like you would for any other kernel object. To signal the event, you use SetEvent, and to reset the event, you use ResetEvent if it is set to be manually reset. Nothing too complicated here. To wait for events, you simply use the normal wait functions like WaitForSingleObject. Obviously after you create an event, you must close the handle when you are done with it. You are also required to close the handle for each time you duplicate one. Most of this stuff applies to all kernel objects because like I mentioned before, the heeders of their structures are the same (they are the same as events).
Many common handle bugs are easily found by just doing a code review. For instance, for each event create, make sure there is a close handle. Make sure you don't close the handle before you are done using it. Etc. If a code review doesn't do it for you, application verifier can auto detect many handle related bugs. Use it, love it.
Windbg: next regular debugging can help a lot to validate your expectations. Next the debugger extension !handle is your friend. I can show detailed information about your handles. Some of the information about handle are only available in KM.
0:000> !handleHandle 4
0:002> !handle 160 7Handle 160