Index: libcfa/src/bits/defs.hfa
===================================================================
--- libcfa/src/bits/defs.hfa	(revision 9d3dc40802c6c907e049db489ed4c138c3298158)
+++ libcfa/src/bits/defs.hfa	(revision a30fceb1a73c4ef2bbee39a2b5406da881f51111)
@@ -26,4 +26,5 @@
 
 typedef void (* fptr_t)();
+typedef uint64_t func_id_t;
 typedef int_fast16_t __lock_size_t;
 
Index: libcfa/src/concurrency/invoke.h
===================================================================
--- libcfa/src/concurrency/invoke.h	(revision 9d3dc40802c6c907e049db489ed4c138c3298158)
+++ libcfa/src/concurrency/invoke.h	(revision a30fceb1a73c4ef2bbee39a2b5406da881f51111)
@@ -159,4 +159,7 @@
 		// last function that acquired monitors
 		fptr_t func;
+
+		// hash-based function identity for cross-TU matching
+		func_id_t func_id;
 	};
 
@@ -288,10 +291,12 @@
 			(this.size){0};
 			(this.func){NULL};
-		}
-
-		static inline void ?{}(__monitor_group_t & this, struct monitor$ ** data, __lock_size_t size, fptr_t func) {
+			(this.func_id){0};
+		}
+
+		static inline void ?{}(__monitor_group_t & this, struct monitor$ ** data, __lock_size_t size, fptr_t func, func_id_t func_id) {
 			(this.data){data};
 			(this.size){size};
 			(this.func){func};
+			(this.func_id){func_id};
 		}
 
@@ -299,5 +304,12 @@
 			if( (lhs.data != 0) != (rhs.data != 0) ) return false;
 			if( lhs.size != rhs.size ) return false;
-			if( lhs.func != rhs.func ) return false;
+			// Use hash-based comparison when both sides have a valid func_id,
+			// otherwise fall back to function pointer comparison (for library code
+			// like join() that cannot compute the hash at compile time).
+			if( lhs.func_id != 0 && rhs.func_id != 0 ) {
+				if( lhs.func_id != rhs.func_id ) return false;
+			} else {
+				if( lhs.func != rhs.func ) return false;
+			}
 
 			// Check that all the monitors match
@@ -314,4 +326,5 @@
 			lhs.size = rhs.size;
 			lhs.func = rhs.func;
+			lhs.func_id = rhs.func_id;
 		}
 	}
Index: libcfa/src/concurrency/kernel/startup.cfa
===================================================================
--- libcfa/src/concurrency/kernel/startup.cfa	(revision 9d3dc40802c6c907e049db489ed4c138c3298158)
+++ libcfa/src/concurrency/kernel/startup.cfa	(revision a30fceb1a73c4ef2bbee39a2b5406da881f51111)
@@ -517,5 +517,5 @@
 	doregister(curr_cluster, this);
 
-	monitors{ &self_mon_p, 1, (fptr_t)0 };
+	monitors{ &self_mon_p, 1, (fptr_t)0, (func_id_t)0 };
 }
 
Index: libcfa/src/concurrency/monitor.cfa
===================================================================
--- libcfa/src/concurrency/monitor.cfa	(revision 9d3dc40802c6c907e049db489ed4c138c3298158)
+++ libcfa/src/concurrency/monitor.cfa	(revision a30fceb1a73c4ef2bbee39a2b5406da881f51111)
@@ -140,5 +140,5 @@
 }
 
-static void __dtor_enter( monitor$ * this, fptr_t func, bool join ) {
+static void __dtor_enter( monitor$ * this, fptr_t func, func_id_t func_id, bool join ) {
 	thread$ * thrd = active_thread();
 	#if defined( __CFA_WITH_VERIFY__ )
@@ -190,5 +190,5 @@
 	__lock_size_t count = 1;
 	monitor$ ** monitors = &this;
-	__monitor_group_t group = { &this, 1, func };
+	__monitor_group_t group = { &this, 1, func, func_id };
 	if ( is_accepted( this, group) ) {
 		__cfaabi_dbg_print_safe( "Kernel : mon accepts dtor, block and signal it \n" );
@@ -341,5 +341,5 @@
 // Ctor for monitor guard
 // Sorts monitors before entering
-void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count, fptr_t func ) libcfa_public {
+void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count, fptr_t func, func_id_t func_id ) libcfa_public {
 	thread$ * thrd = active_thread();
 
@@ -355,10 +355,10 @@
 
 	// Update thread context (needed for conditions)
-	(thrd->monitors){m, count, func};
+	(thrd->monitors){m, count, func, func_id};
 
 	// __cfaabi_dbg_print_safe( "MGUARD : enter %d\n", count);
 
 	// Enter the monitors in order
-	__monitor_group_t group = {this.m, this.count, func};
+	__monitor_group_t group = {this.m, this.count, func, func_id};
 	enter( group );
 
@@ -367,5 +367,5 @@
 
 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count ) libcfa_public {
-	this{ m, count, 0p };
+	this{ m, count, 0p, 0 };
 }
 
@@ -386,5 +386,5 @@
 // Ctor for monitor guard
 // Sorts monitors before entering
-void ?{}( monitor_dtor_guard_t & this, monitor$ * m [], fptr_t func, bool join ) libcfa_public {
+void ?{}( monitor_dtor_guard_t & this, monitor$ * m [], fptr_t func, func_id_t func_id, bool join ) libcfa_public {
 	// optimization
 	thread$ * thrd = active_thread();
@@ -400,7 +400,7 @@
 
 	// Update thread context (needed for conditions)
-	(thrd->monitors){m, 1, func};
-
-	__dtor_enter( this.m, func, join );
+	(thrd->monitors){m, 1, func, func_id};
+
+	__dtor_enter( this.m, func, func_id, join );
 }
 
Index: libcfa/src/concurrency/monitor.hfa
===================================================================
--- libcfa/src/concurrency/monitor.hfa	(revision 9d3dc40802c6c907e049db489ed4c138c3298158)
+++ libcfa/src/concurrency/monitor.hfa	(revision a30fceb1a73c4ef2bbee39a2b5406da881f51111)
@@ -48,5 +48,5 @@
 };
 
-void ?{}( monitor_guard_t & this, monitor$ ** m, __lock_size_t count, void (*func)() );
+void ?{}( monitor_guard_t & this, monitor$ ** m, __lock_size_t count, void (*func)(), func_id_t func_id );
 void ?{}( monitor_guard_t & this, monitor$ ** m, __lock_size_t count );
 void ^?{}( monitor_guard_t & this );
@@ -58,5 +58,5 @@
 };
 
-void ?{}( monitor_dtor_guard_t & this, monitor$ ** m, void (*func)(), bool join );
+void ?{}( monitor_dtor_guard_t & this, monitor$ ** m, void (*func)(), func_id_t func_id, bool join );
 void ^?{}( monitor_dtor_guard_t & this );
 
Index: libcfa/src/concurrency/thread.cfa
===================================================================
--- libcfa/src/concurrency/thread.cfa	(revision 9d3dc40802c6c907e049db489ed4c138c3298158)
+++ libcfa/src/concurrency/thread.cfa	(revision a30fceb1a73c4ef2bbee39a2b5406da881f51111)
@@ -61,5 +61,5 @@
 
 	doregister(curr_cluster, this);
-	monitors{ &self_mon_p, 1, (fptr_t)0 };
+	monitors{ &self_mon_p, 1, (fptr_t)0, (func_id_t)0 };
 }
 
@@ -93,5 +93,5 @@
     | { EHM_DEFAULT_VTABLE(ThreadCancelled(T)); })
 void ?{}( thread_dtor_guard_t & this,
-		T & thrd, void(*cancelHandler)(ThreadCancelled(T) &)) {
+		T & thrd, func_id_t func_id, void(*cancelHandler)(ThreadCancelled(T) &)) {
 	monitor$ * m = get_monitor(thrd);
 	thread$ * desc = get_thread(thrd);
@@ -100,5 +100,6 @@
 	void (*dtor)(T& mutex this) = ^?{};
 	bool join = cancelHandler != (void(*)(ThreadCancelled(T)&))0;
-	(this.mg){&m, (void(*)())dtor, join};
+	this.func_id = func_id;
+	(this.mg){&m, (void(*)())dtor, func_id, join};
 
 
@@ -172,5 +173,5 @@
 	| { EHM_DEFAULT_VTABLE(ThreadCancelled(T)); })
 T & join( T & this ) {
-	thread_dtor_guard_t guard = { this, defaultResumptionHandler };
+	thread_dtor_guard_t guard = { this, (func_id_t)0, defaultResumptionHandler };
 	return this;
 }
Index: libcfa/src/concurrency/thread.hfa
===================================================================
--- libcfa/src/concurrency/thread.hfa	(revision 9d3dc40802c6c907e049db489ed4c138c3298158)
+++ libcfa/src/concurrency/thread.hfa	(revision a30fceb1a73c4ef2bbee39a2b5406da881f51111)
@@ -83,9 +83,10 @@
 struct thread_dtor_guard_t {
 	monitor_dtor_guard_t mg;
+	func_id_t func_id;
 };
 
 forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled(T))
 	| { EHM_DEFAULT_VTABLE(ThreadCancelled(T)); })
-void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
+void ?{}( thread_dtor_guard_t & this, T & thrd, func_id_t func_id, void(*)(ThreadCancelled(T) &) );
 void ^?{}( thread_dtor_guard_t & this );
 
