Mercurial > hg > orthanc
changeset 7110:5200f9e88bcd
added class SequentialExecutorService
line wrap: on
line diff
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/Resources/CMake/OrthancFrameworkConfiguration.cmake Fri Aug 14 10:02:41 2026 +0200 @@ -181,6 +181,7 @@ ${CMAKE_CURRENT_LIST_DIR}/../../Sources/HttpServer/StringMatcher.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/Logging.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MallocMemoryBuffer.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MultiThreading/SequentialExecutorService.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/OrthancException.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/OrthancFramework.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/RestApi/RestApiHierarchy.cpp @@ -667,8 +668,8 @@ ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MetricsRegistry.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MultiThreading/BlockingSharedMessageQueue.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MultiThreading/CallableGroup.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MultiThreading/Future.cpp - ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MultiThreading/FutureState.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MultiThreading/Internals/FutureState.cpp + ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MultiThreading/Internals/ThreadPoolFuture.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MultiThreading/RunnableWorkersPool.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MultiThreading/Semaphore.cpp ${CMAKE_CURRENT_LIST_DIR}/../../Sources/MultiThreading/SharedMessageQueue.cpp
--- a/OrthancFramework/Sources/DataSource/DataSourceSequentialReader.cpp Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/Sources/DataSource/DataSourceSequentialReader.cpp Fri Aug 14 10:02:41 2026 +0200 @@ -322,7 +322,7 @@ } else { - std::unique_ptr<Future> future(runningRequests_.front()); + std::unique_ptr<IFuture> future(runningRequests_.front()); runningRequests_.pop_front(); std::unique_ptr<Item> item(dynamic_cast<Item*>(future->ReleaseResult()));
--- a/OrthancFramework/Sources/DataSource/DataSourceSequentialReader.h Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/Sources/DataSource/DataSourceSequentialReader.h Fri Aug 14 10:02:41 2026 +0200 @@ -110,7 +110,7 @@ class Callable; typedef std::list<IDataIdentifier*> PendingRequests; - typedef std::list<Future*> RunningRequests; + typedef std::list<IFuture*> RunningRequests; boost::shared_ptr<IExecutorService> executor_; boost::shared_ptr<DataSourceReader> reader_;
--- a/OrthancFramework/Sources/DataSource/DicomSequentialReader.h Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/Sources/DataSource/DicomSequentialReader.h Fri Aug 14 10:02:41 2026 +0200 @@ -29,6 +29,8 @@ #include "../IMemoryBuffer.h" #include "../MultiThreading/IExecutorService.h" +#include <boost/shared_ptr.hpp> + namespace Orthanc {
--- a/OrthancFramework/Sources/MultiThreading/CallableGroup.cpp Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/Sources/MultiThreading/CallableGroup.cpp Fri Aug 14 10:02:41 2026 +0200 @@ -65,7 +65,7 @@ delete *it; } - for (std::list<Future*>::iterator it = futures_.begin(); it != futures_.end(); ++it) + for (std::list<IFuture*>::iterator it = futures_.begin(); it != futures_.end(); ++it) { assert(*it != NULL); delete *it; @@ -119,7 +119,7 @@ std::unique_ptr<IDynamicObject> result; { - std::unique_ptr<Future> future(that_.futures_.front()); + std::unique_ptr<IFuture> future(that_.futures_.front()); assert(future.get() != NULL); result.reset(future->ReleaseResult());
--- a/OrthancFramework/Sources/MultiThreading/CallableGroup.h Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/Sources/MultiThreading/CallableGroup.h Fri Aug 14 10:02:41 2026 +0200 @@ -26,6 +26,7 @@ #include "IExecutorService.h" +#include <boost/shared_ptr.hpp> #include <list> @@ -38,7 +39,7 @@ boost::shared_ptr<IExecutorService> executor_; unsigned int windowSize_; std::list<ICallable*> pending_; - std::list<Future*> futures_; + std::list<IFuture*> futures_; bool hasIterator_; void FillWindow();
--- a/OrthancFramework/Sources/MultiThreading/Future.cpp Fri Aug 14 09:16:55 2026 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "Future.h" - -#include "FutureState.h" -#include "../OrthancException.h" - -namespace Orthanc -{ - Future::Future(boost::shared_ptr<Internals::FutureState>& state) : - state_(state) - { - if (state.get() == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - } - - Future::~Future() - { - state_->Cancel(); - } - - IDynamicObject* Future::ReleaseResult() - { - return state_->ReleaseResult(); - } -}
--- a/OrthancFramework/Sources/MultiThreading/Future.h Fri Aug 14 09:16:55 2026 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "../IDynamicObject.h" - -#include <boost/shared_ptr.hpp> - -namespace Orthanc -{ - namespace Internals - { - class FutureState; - } - - class ORTHANC_PUBLIC Future : public boost::noncopyable - { - friend class ThreadPool; - - private: - boost::shared_ptr<Internals::FutureState> state_; - - explicit Future(boost::shared_ptr<Internals::FutureState>& state); - - public: - ~Future(); - - IDynamicObject* ReleaseResult(); - }; -}
--- a/OrthancFramework/Sources/MultiThreading/FutureState.cpp Fri Aug 14 09:16:55 2026 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/>. - **/ - - -#include "../PrecompiledHeaders.h" -#include "FutureState.h" - -#include <cassert> - - -namespace Orthanc -{ - namespace Internals - { - IDynamicObject* FutureState::ReleaseInternal(bool hasTimeout, - unsigned int millisecondsTimeout) - { - boost::mutex::scoped_lock lock(mutex_); - - for (;;) - { - switch (state_) - { - case State_Pending: - if (hasTimeout) - { - bool success = completed_.timed_wait(lock, boost::posix_time::milliseconds(millisecondsTimeout)); - if (success) - { - if (state_ != State_Success && - state_ != State_Failed) - { - THROW_WITH_FILE_AND_LINE_INFO(ErrorCode_InternalError); // Should never happen - } - } - } - else - { - completed_.wait(lock); - } - break; - - case State_Canceled: - throw OrthancException(ErrorCode_CanceledJob); - - case State_Failed: - if (error_.get() == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, "The result of the future has already been released"); - } - else - { - std::unique_ptr<OrthancException> released(error_.release()); - throw OrthancException(*released); - } - - case State_Success: - if (result_.get() == NULL) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls, "The result of the future has already been released"); - } - else - { - return result_.release(); - } - - default: - THROW_WITH_FILE_AND_LINE_INFO(ErrorCode_InternalError); // Should never happen - } - } - } - - - void FutureState::Cancel() ORTHANC_NOEXCEPT - { - boost::mutex::scoped_lock lock(mutex_); - - if (state_ == State_Pending) - { - state_ = State_Canceled; - completed_.notify_all(); - } - } - - - void FutureState::AcquireResult(IDynamicObject* result) - { - std::unique_ptr<IDynamicObject> protection(result); - - if (result == NULL) - { - throw OrthancException(ErrorCode_NullPointer); - } - else - { - boost::mutex::scoped_lock lock(mutex_); - - switch (state_) - { - case State_Pending: - assert(result_.get() == NULL); - assert(error_.get() == NULL); - - result_.reset(protection.release()); - state_ = State_Success; - completed_.notify_all(); - break; - - case State_Canceled: - break; // Ignore - - case State_Failed: - case State_Success: - throw OrthancException(ErrorCode_BadSequenceOfCalls); - - default: - THROW_WITH_FILE_AND_LINE_INFO(ErrorCode_InternalError); // Should never happen - } - } - } - - - void FutureState::SetError(const OrthancException& error) - { - boost::mutex::scoped_lock lock(mutex_); - - switch (state_) - { - case State_Pending: - assert(result_.get() == NULL); - assert(error_.get() == NULL); - - error_.reset(new OrthancException(error)); - state_ = State_Failed; - completed_.notify_all(); - break; - - case State_Canceled: - break; // Ignore - - case State_Failed: - case State_Success: - throw OrthancException(ErrorCode_BadSequenceOfCalls); - - default: - THROW_WITH_FILE_AND_LINE_INFO(ErrorCode_InternalError); // Should never happen - } - } - } -}
--- a/OrthancFramework/Sources/MultiThreading/FutureState.h Fri Aug 14 09:16:55 2026 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium - * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "../Compatibility.h" -#include "../IDynamicObject.h" -#include "../OrthancException.h" - -#include <boost/thread/mutex.hpp> -#include <boost/thread/condition_variable.hpp> - -namespace Orthanc -{ - namespace Internals - { - class FutureState : public boost::noncopyable - { - public: - enum State - { - State_Pending, - State_Success, - State_Failed, - State_Canceled - }; - - private: - boost::mutex mutex_; - boost::condition_variable completed_; - State state_; - std::unique_ptr<IDynamicObject> result_; - std::unique_ptr<OrthancException> error_; - - IDynamicObject* ReleaseInternal(bool hasTimeout, - unsigned int millisecondsTimeout); - - public: - FutureState() : - state_(State_Pending) - { - } - - IDynamicObject* ReleaseResult() - { - return ReleaseInternal(false, 0); - } - - IDynamicObject* ReleaseResult(unsigned int millisecondsTimeout) - { - return ReleaseInternal(true, millisecondsTimeout); - } - - void Cancel() ORTHANC_NOEXCEPT; - - void AcquireResult(IDynamicObject* result /* takes ownership */); - - void SetError(const OrthancException& error); - }; - } -}
--- a/OrthancFramework/Sources/MultiThreading/IExecutorService.h Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/Sources/MultiThreading/IExecutorService.h Fri Aug 14 10:02:41 2026 +0200 @@ -24,7 +24,7 @@ #pragma once -#include "Future.h" +#include "IFuture.h" #include "ICallable.h" #include "IRunnable.h" @@ -38,7 +38,7 @@ { } - virtual Future* Submit(ICallable* callable /* takes ownership */) = 0; + virtual IFuture* Submit(ICallable* callable /* takes ownership */) = 0; virtual void Submit(IRunnable* runnable /* takes ownership */) = 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Sources/MultiThreading/Internals/FutureState.cpp Fri Aug 14 10:02:41 2026 +0200 @@ -0,0 +1,170 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#include "../../PrecompiledHeaders.h" +#include "FutureState.h" + +#include <cassert> + + +namespace Orthanc +{ + namespace Internals + { + IDynamicObject* FutureState::ReleaseInternal(bool hasTimeout, + unsigned int millisecondsTimeout) + { + boost::mutex::scoped_lock lock(mutex_); + + for (;;) + { + switch (state_) + { + case State_Pending: + if (hasTimeout) + { + bool success = completed_.timed_wait(lock, boost::posix_time::milliseconds(millisecondsTimeout)); + if (success) + { + if (state_ != State_Success && + state_ != State_Failed) + { + THROW_WITH_FILE_AND_LINE_INFO(ErrorCode_InternalError); // Should never happen + } + } + } + else + { + completed_.wait(lock); + } + break; + + case State_Canceled: + throw OrthancException(ErrorCode_CanceledJob); + + case State_Failed: + if (error_.get() == NULL) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls, "The result of the future has already been released"); + } + else + { + std::unique_ptr<OrthancException> released(error_.release()); + throw OrthancException(*released); + } + + case State_Success: + if (result_.get() == NULL) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls, "The result of the future has already been released"); + } + else + { + return result_.release(); + } + + default: + THROW_WITH_FILE_AND_LINE_INFO(ErrorCode_InternalError); // Should never happen + } + } + } + + + void FutureState::Cancel() ORTHANC_NOEXCEPT + { + boost::mutex::scoped_lock lock(mutex_); + + if (state_ == State_Pending) + { + state_ = State_Canceled; + completed_.notify_all(); + } + } + + + void FutureState::AcquireResult(IDynamicObject* result) + { + std::unique_ptr<IDynamicObject> protection(result); + + if (result == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + else + { + boost::mutex::scoped_lock lock(mutex_); + + switch (state_) + { + case State_Pending: + assert(result_.get() == NULL); + assert(error_.get() == NULL); + + result_.reset(protection.release()); + state_ = State_Success; + completed_.notify_all(); + break; + + case State_Canceled: + break; // Ignore + + case State_Failed: + case State_Success: + throw OrthancException(ErrorCode_BadSequenceOfCalls); + + default: + THROW_WITH_FILE_AND_LINE_INFO(ErrorCode_InternalError); // Should never happen + } + } + } + + + void FutureState::SetError(const OrthancException& error) + { + boost::mutex::scoped_lock lock(mutex_); + + switch (state_) + { + case State_Pending: + assert(result_.get() == NULL); + assert(error_.get() == NULL); + + error_.reset(new OrthancException(error)); + state_ = State_Failed; + completed_.notify_all(); + break; + + case State_Canceled: + break; // Ignore + + case State_Failed: + case State_Success: + throw OrthancException(ErrorCode_BadSequenceOfCalls); + + default: + THROW_WITH_FILE_AND_LINE_INFO(ErrorCode_InternalError); // Should never happen + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Sources/MultiThreading/Internals/FutureState.h Fri Aug 14 10:02:41 2026 +0200 @@ -0,0 +1,82 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../../Compatibility.h" +#include "../../IDynamicObject.h" +#include "../../OrthancException.h" + +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> + +namespace Orthanc +{ + namespace Internals + { + class FutureState : public boost::noncopyable + { + public: + enum State + { + State_Pending, + State_Success, + State_Failed, + State_Canceled + }; + + private: + boost::mutex mutex_; + boost::condition_variable completed_; + State state_; + std::unique_ptr<IDynamicObject> result_; + std::unique_ptr<OrthancException> error_; + + IDynamicObject* ReleaseInternal(bool hasTimeout, + unsigned int millisecondsTimeout); + + public: + FutureState() : + state_(State_Pending) + { + } + + IDynamicObject* ReleaseResult() + { + return ReleaseInternal(false, 0); + } + + IDynamicObject* ReleaseResult(unsigned int millisecondsTimeout) + { + return ReleaseInternal(true, millisecondsTimeout); + } + + void Cancel() ORTHANC_NOEXCEPT; + + void AcquireResult(IDynamicObject* result /* takes ownership */); + + void SetError(const OrthancException& error); + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Sources/MultiThreading/Internals/ThreadPoolFuture.cpp Fri Aug 14 10:02:41 2026 +0200 @@ -0,0 +1,54 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#include "../../PrecompiledHeaders.h" +#include "ThreadPoolFuture.h" + +#include "FutureState.h" +#include "../../OrthancException.h" + +namespace Orthanc +{ + namespace Internals + { + ThreadPoolFuture::ThreadPoolFuture(boost::shared_ptr<FutureState>& state) : + state_(state) + { + if (state.get() == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + } + + ThreadPoolFuture::~ThreadPoolFuture() + { + state_->Cancel(); + } + + IDynamicObject* ThreadPoolFuture::ReleaseResult() + { + return state_->ReleaseResult(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Sources/MultiThreading/Internals/ThreadPoolFuture.h Fri Aug 14 10:02:41 2026 +0200 @@ -0,0 +1,49 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../IFuture.h" +#include "FutureState.h" + +#include <boost/shared_ptr.hpp> + +namespace Orthanc +{ + namespace Internals + { + class ORTHANC_PUBLIC ThreadPoolFuture : public IFuture + { + private: + boost::shared_ptr<FutureState> state_; + + public: + explicit ThreadPoolFuture(boost::shared_ptr<FutureState>& state); + + virtual ~ThreadPoolFuture(); + + IDynamicObject* ReleaseResult() ORTHANC_OVERRIDE; + }; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Sources/MultiThreading/SequentialExecutorService.cpp Fri Aug 14 10:02:41 2026 +0200 @@ -0,0 +1,112 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#include "../PrecompiledHeaders.h" +#include "SequentialExecutorService.h" + +#include "../OrthancException.h" + + +namespace Orthanc +{ + class SequentialExecutorService::Future : public IFuture + { + private: + std::unique_ptr<IDynamicObject> value_; + + public: + Future(IDynamicObject* value) : + value_(value) + { + if (value_ == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + } + + virtual IDynamicObject* ReleaseResult() ORTHANC_OVERRIDE + { + return value_.release(); + } + }; + + + SequentialExecutorService::SequentialExecutorService() : + working_(true) + { + } + + + bool SequentialExecutorService::IsWorking() + { + Mutex::ScopedLock lock(mutex_); + return working_; + } + + + IFuture* SequentialExecutorService::Submit(ICallable* callable /* takes ownership */) + { + Mutex::ScopedLock lock(mutex_); + + if (working_) + { + return new Future(callable->Call()); + } + else + { + throw OrthancException(ErrorCode_InternalError); + } + } + + + void SequentialExecutorService::Submit(IRunnable* runnable /* takes ownership */) + { + Mutex::ScopedLock lock(mutex_); + + if (runnable == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + else + { + std::unique_ptr<IRunnable> protection(runnable); + protection->Run(); + } + } + + + void SequentialExecutorService::Stop() + { + Mutex::ScopedLock lock(mutex_); + + if (working_) + { + working_ = false; + } + else + { + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancFramework/Sources/MultiThreading/SequentialExecutorService.h Fri Aug 14 10:02:41 2026 +0200 @@ -0,0 +1,53 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2026 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "../Compatibility.h" +#include "IExecutorService.h" +#include "Mutex.h" + + +namespace Orthanc +{ + class SequentialExecutorService : public IExecutorService + { + private: + class Future; + + Mutex mutex_; + bool working_; + + public: + SequentialExecutorService(); + + bool IsWorking(); + + virtual IFuture* Submit(ICallable* callable /* takes ownership */) ORTHANC_OVERRIDE; + + virtual void Submit(IRunnable* runnable /* takes ownership */) ORTHANC_OVERRIDE; + + virtual void Stop() ORTHANC_OVERRIDE; + }; +}
--- a/OrthancFramework/Sources/MultiThreading/ThreadPool.cpp Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/Sources/MultiThreading/ThreadPool.cpp Fri Aug 14 10:02:41 2026 +0200 @@ -26,10 +26,11 @@ #include "ThreadPool.h" #include "../Logging.h" +#include "../MetricsRegistry.h" #include "../OrthancException.h" -#include "../MetricsRegistry.h" #include "../Toolbox.h" -#include "FutureState.h" +#include "Internals/FutureState.h" +#include "Internals/ThreadPoolFuture.h" #include <boost/lexical_cast.hpp> #include <boost/weak_ptr.hpp> @@ -389,7 +390,7 @@ } - Future* ThreadPool::Submit(ICallable* callable) + IFuture* ThreadPool::Submit(ICallable* callable) { std::unique_ptr<ICallable> protection(callable); @@ -411,7 +412,7 @@ queue_.Enqueue(new CallableTask(protection.release(), state)); - return new Future(state); + return new Internals::ThreadPoolFuture(state); }
--- a/OrthancFramework/Sources/MultiThreading/ThreadPool.h Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/Sources/MultiThreading/ThreadPool.h Fri Aug 14 10:02:41 2026 +0200 @@ -82,7 +82,7 @@ void Start(); - virtual Future* Submit(ICallable* callable /* takes ownership */) ORTHANC_OVERRIDE; + virtual IFuture* Submit(ICallable* callable /* takes ownership */) ORTHANC_OVERRIDE; virtual void Submit(IRunnable* runnable /* takes ownership */) ORTHANC_OVERRIDE;
--- a/OrthancFramework/UnitTestsSources/DataSourceTests.cpp Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/UnitTestsSources/DataSourceTests.cpp Fri Aug 14 10:02:41 2026 +0200 @@ -30,10 +30,13 @@ #include <gtest/gtest.h> #include "../Sources/DataSource/DataSourceReader.h" +#include "../Sources/MultiThreading/SequentialExecutorService.h" +#include "../Sources/OrthancException.h" + using namespace Orthanc; -TEST(DataSources, Basic) +TEST(DataSource, Basic) { }
--- a/OrthancFramework/UnitTestsSources/JobsTests.cpp Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancFramework/UnitTestsSources/JobsTests.cpp Fri Aug 14 10:02:41 2026 +0200 @@ -1860,8 +1860,8 @@ pool.Start(); { - std::unique_ptr<Future> future1(pool.Submit(new CountCallable)); - std::unique_ptr<Future> future2(pool.Submit(new ExceptionCallable)); + std::unique_ptr<IFuture> future1(pool.Submit(new CountCallable)); + std::unique_ptr<IFuture> future2(pool.Submit(new ExceptionCallable)); { std::unique_ptr<IDynamicObject> result(future1->ReleaseResult());
--- a/OrthancServer/Sources/ServerContext.h Fri Aug 14 09:16:55 2026 +0200 +++ b/OrthancServer/Sources/ServerContext.h Fri Aug 14 10:02:41 2026 +0200 @@ -36,7 +36,6 @@ #include "../../OrthancFramework/Sources/DicomParsing/DicomModification.h" #include "../../OrthancFramework/Sources/JobsEngine/JobsEngine.h" #include "../../OrthancFramework/Sources/MetricsRegistry.h" -#include "../../OrthancFramework/Sources/MultiThreading/Future.h" #include "../../OrthancFramework/Sources/MultiThreading/Semaphore.h"
