The fundamental reason for the mutex in a condition variable + mutex combination is to provide protection to the predicate data.
Read this carefully.
Condition variables are a signaling mechanism. That's all. The thing they signal you for is a prospective change in some external predicate condition that you, as a waiter, have subscribed to be interested in. When you are eventually awoken you own the mutex, and thus with it exclusive rights to the predicate data. This is vital. So long as all threads that need to access the predicate data play by the rules and no thread ever accesses the predicate data in any way without owning the underlying mutex, everything works.
The part that is noteworthy to you, the application developer, and is equally vital: The action of waiting on a condition variable atomically (as far as you're concerned, anyway) begins the wait and unlatches the mutex to allow other waiters access to obtain it, and therefore sanctioned access to the predicate data. Generic Windows events have nothing like this until Server 2008 and Vista). The closest thing I can describe how it would have to work on Windows is unlocking a hMutex
and beginning to wait on an hEvent
atomically, thereby eliminating the potential of change sneaking in between the two operations.
This is vital because it eliminates the race condition of a typical unprotected set-and-test. Said-race condition without the atomic unlatch-and-wait causes significant problems. Ex: you own the mutex, check the data, not what you need, so you unlock the mutex an wait for an event. It is conceivable that between the time you unlatch the mutex and actually begin the wait-operation the condition you're waiting on happens in that slice of time. And you missed it. That won't happen when properly waiting with a cvar-mtx combo.
Above all remember this. Condition variables don't hold "state" as you may think. The predicate state is held in data variables of your own design. Protecting that state is the primary job of the associated mutex. You don't need to own the predicate data mutex to signal a condition change. But you do need to own the mutex to actually make that change. If you don't, you're playing with fire.
EDIT: given the now-edited premise of the question (a signally mechanism only with no shared predicate data), I wouldn't use a condition variable + mutex combo in the first place. I'd use a blocking pipe and write a byte to it when the "signal" needed to be sent. And you can't design the interface with a coupled cvar+mutex "entity", as there are times when you want to change predicate data and NOT signal the prospective waiters. you can do that latching only the mutex and making the change without invoking the signal. Were they coupled, you wouldn't have that luxury.