diff --git a/include/libcamera/base/thread.h b/include/libcamera/base/thread.h
index 3cbf6398..b9284c2c 100644
--- a/include/libcamera/base/thread.h
+++ b/include/libcamera/base/thread.h
@@ -48,7 +48,8 @@ public:
 
 	EventDispatcher *eventDispatcher();
 
-	void dispatchMessages(Message::Type type = Message::Type::None);
+	void dispatchMessages(Message::Type type = Message::Type::None,
+			      Object *receiver = nullptr);
 
 protected:
 	int exec();
diff --git a/src/libcamera/base/thread.cpp b/src/libcamera/base/thread.cpp
index 02128f23..2fde2959 100644
--- a/src/libcamera/base/thread.cpp
+++ b/src/libcamera/base/thread.cpp
@@ -603,6 +603,8 @@ void Thread::removeMessages(Object *receiver)
 /**
  * \brief Dispatch posted messages for this thread
  * \param[in] type The message type
+ * \param[in] receiver If not null, dispatch only messages for the given
+ *    receiver
  *
  * This function immediately dispatches all the messages previously posted for
  * this thread with postMessage() that match the message \a type. If the \a type
@@ -616,7 +618,7 @@ void Thread::removeMessages(Object *receiver)
  * same thread from an object's message handler. It guarantees delivery of
  * messages in the order they have been posted in all cases.
  */
-void Thread::dispatchMessages(Message::Type type)
+void Thread::dispatchMessages(Message::Type type, Object *receiver)
 {
 	ASSERT(data_ == ThreadData::current());
 
@@ -640,12 +642,14 @@ void Thread::dispatchMessages(Message::Type type)
 		 */
 		std::unique_ptr<Message> message = std::move(msg);
 
-		Object *receiver = message->receiver_;
-		ASSERT(data_ == receiver->thread()->data_);
-		receiver->pendingMessages_--;
+		Object *messageReceiver = message->receiver_;
+		if (receiver && receiver != messageReceiver)
+			continue;
+		ASSERT(data_ == messageReceiver->thread()->data_);
+		messageReceiver->pendingMessages_--;
 
 		locker.unlock();
-		receiver->message(message.get());
+		messageReceiver->message(message.get());
 		message.reset();
 		locker.lock();
 	}
diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
index 3a605ab2..8f5ee774 100644
--- a/src/libcamera/software_isp/software_isp.cpp
+++ b/src/libcamera/software_isp/software_isp.cpp
@@ -13,6 +13,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <libcamera/base/thread.h>
+
 #include <libcamera/controls.h>
 #include <libcamera/formats.h>
 #include <libcamera/stream.h>
@@ -339,6 +341,7 @@ void SoftwareIsp::stop()
 	ispWorkerThread_.wait();
 
 	running_ = false;
+	Thread::current()->dispatchMessages(Message::Type::InvokeMessage, this);
 	ipa_->stop();
 
 	for (auto buffer : queuedOutputBuffers_) {
diff --git a/utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl b/utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl
index b5797b14..25476990 100644
--- a/utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl
+++ b/utils/codegen/ipc/generators/libcamera_templates/proxy_functions.tmpl
@@ -34,7 +34,7 @@
 	thread_.exit();
 	thread_.wait();
 
-	Thread::current()->dispatchMessages(Message::Type::InvokeMessage);
+	Thread::current()->dispatchMessages(Message::Type::InvokeMessage, this);
 
 	state_ = ProxyStopped;
 {%- endmacro -%}
