diff --git a/qse/include/qse/si/Condition.hpp b/qse/include/qse/si/Condition.hpp new file mode 100644 index 00000000..b0c9ee33 --- /dev/null +++ b/qse/include/qse/si/Condition.hpp @@ -0,0 +1,68 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EQSERESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QSE_SI_CONDITION_CLASS_ +#define _QSE_SI_CONDITION_CLASS_ + +#include +#include + +QSE_BEGIN_NAMESPACE(QSE) + +class Condition: public Uncopyable +{ +public: + Condition() QSE_CPP_NOEXCEPT + { + qse_cnd_init (&this->cnd, QSE_NULL); + } + ~Condition() QSE_CPP_NOEXCEPT + { + qse_cnd_fini (&this->cnd); + } + + void signal () + { + qse_cnd_signal (&this->cnd); + } + + void broadcast () + { + qse_cnd_broadcast (&this->cnd); + } + + void wait (Mutex& mtx, const qse_ntime_t* timeout = QSE_NULL) + { + qse_cnd_wait (&this->cnd, &mtx.mtx, timeout); + } + +protected: + qse_cnd_t cnd; +}; + +QSE_END_NAMESPACE(QSE) + +#endif diff --git a/qse/include/qse/si/Makefile.am b/qse/include/qse/si/Makefile.am index 4e80e040..448d742c 100644 --- a/qse/include/qse/si/Makefile.am +++ b/qse/include/qse/si/Makefile.am @@ -30,6 +30,7 @@ pkginclude_HEADERS = \ if ENABLE_CXX pkginclude_HEADERS += \ AppRoot.hpp \ + Condition.hpp \ Mutex.hpp \ SocketAddress.hpp \ Socket.hpp \ diff --git a/qse/include/qse/si/Makefile.in b/qse/include/qse/si/Makefile.in index e8f9b4b5..933240c4 100644 --- a/qse/include/qse/si/Makefile.in +++ b/qse/include/qse/si/Makefile.in @@ -89,6 +89,7 @@ build_triplet = @build@ host_triplet = @host@ @ENABLE_CXX_TRUE@am__append_1 = \ @ENABLE_CXX_TRUE@ AppRoot.hpp \ +@ENABLE_CXX_TRUE@ Condition.hpp \ @ENABLE_CXX_TRUE@ Mutex.hpp \ @ENABLE_CXX_TRUE@ SocketAddress.hpp \ @ENABLE_CXX_TRUE@ Socket.hpp \ @@ -135,8 +136,8 @@ am__can_run_installinfo = \ am__pkginclude_HEADERS_DIST = aio.h aio-pro.h aio-sck.h cnd.h dir.h \ fio.h fs.h glob.h intr.h log.h mtx.h mux.h nwad.h nwif.h \ nwio.h os.h pio.h rwl.h sck.h sinfo.h sio.h spl.h task.h thr.h \ - tio.h AppRoot.hpp Mutex.hpp SocketAddress.hpp Socket.hpp \ - SpinLock.hpp TcpServer.hpp Thread.hpp + tio.h AppRoot.hpp Condition.hpp Mutex.hpp SocketAddress.hpp \ + Socket.hpp SpinLock.hpp TcpServer.hpp Thread.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ diff --git a/qse/include/qse/si/Mutex.hpp b/qse/include/qse/si/Mutex.hpp index 1e37ce65..0c87affc 100644 --- a/qse/include/qse/si/Mutex.hpp +++ b/qse/include/qse/si/Mutex.hpp @@ -36,6 +36,8 @@ QSE_BEGIN_NAMESPACE(QSE) class Mutex: public Uncopyable { public: + friend class Condition; + Mutex() QSE_CPP_NOEXCEPT { qse_mtx_init (&this->mtx, QSE_NULL); diff --git a/qse/include/qse/si/cnd.h b/qse/include/qse/si/cnd.h index 25692317..fe032054 100644 --- a/qse/include/qse/si/cnd.h +++ b/qse/include/qse/si/cnd.h @@ -134,6 +134,11 @@ QSE_EXPORT void qse_cnd_broadcast ( qse_cnd_t* cond ); +/** + * The qse_cnd_wait() function blocks the calling thread until the condition + * variable is signaled. The caller must lock the mutex before calling this + * function and unlock the mutex after this function finishes. + */ QSE_EXPORT void qse_cnd_wait ( qse_cnd_t* cond, qse_mtx_t* mutex, diff --git a/qse/samples/si/Makefile.am b/qse/samples/si/Makefile.am index 8b10d3fa..ffcc6458 100644 --- a/qse/samples/si/Makefile.am +++ b/qse/samples/si/Makefile.am @@ -65,17 +65,19 @@ if ENABLE_CXX CXXLIB = -lqsesixx -lqsecmnxx -bin_PROGRAMS += sck01 spl02 tcpsvr01 thr02 +bin_PROGRAMS += sck01 spl02 tcpsvr01 thr02 thr03 sck01_SOURCES = sck01.cpp spl02_SOURCES = spl02.cpp tcpsvr01_SOURCES = tcpsvr01.cpp thr02_SOURCES = thr02.cpp +thr03_SOURCES = thr03.cpp sck01_LDADD = $(CXXLIB) $(LDADD) spl02_LDADD = $(CXXLIB) $(LDADD) tcpsvr01_LDADD = $(CXXLIB) $(LDADD) thr02_LDADD = $(CXXLIB) $(LDADD) +thr03_LDADD = $(CXXLIB) $(LDADD) endif diff --git a/qse/samples/si/Makefile.in b/qse/samples/si/Makefile.in index 1ee5ac3a..f57a8e00 100644 --- a/qse/samples/si/Makefile.in +++ b/qse/samples/si/Makefile.in @@ -95,7 +95,7 @@ bin_PROGRAMS = aio01$(EXEEXT) dir01$(EXEEXT) fio01$(EXEEXT) \ sio01$(EXEEXT) sio02$(EXEEXT) sio03$(EXEEXT) spl01$(EXEEXT) \ task01$(EXEEXT) thr01$(EXEEXT) $(am__EXEEXT_1) @WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS) -@ENABLE_CXX_TRUE@am__append_2 = sck01 spl02 tcpsvr01 thr02 +@ENABLE_CXX_TRUE@am__append_2 = sck01 spl02 tcpsvr01 thr02 thr03 subdir = samples/si ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_sign.m4 \ @@ -113,7 +113,8 @@ CONFIG_HEADER = $(top_builddir)/include/qse/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @ENABLE_CXX_TRUE@am__EXEEXT_1 = sck01$(EXEEXT) spl02$(EXEEXT) \ -@ENABLE_CXX_TRUE@ tcpsvr01$(EXEEXT) thr02$(EXEEXT) +@ENABLE_CXX_TRUE@ tcpsvr01$(EXEEXT) thr02$(EXEEXT) \ +@ENABLE_CXX_TRUE@ thr03$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_aio01_OBJECTS = aio01.$(OBJEXT) @@ -223,6 +224,11 @@ am__thr02_SOURCES_DIST = thr02.cpp thr02_OBJECTS = $(am_thr02_OBJECTS) @ENABLE_CXX_TRUE@thr02_DEPENDENCIES = $(am__DEPENDENCIES_1) \ @ENABLE_CXX_TRUE@ $(am__DEPENDENCIES_3) +am__thr03_SOURCES_DIST = thr03.cpp +@ENABLE_CXX_TRUE@am_thr03_OBJECTS = thr03.$(OBJEXT) +thr03_OBJECTS = $(am_thr03_OBJECTS) +@ENABLE_CXX_TRUE@thr03_DEPENDENCIES = $(am__DEPENDENCIES_1) \ +@ENABLE_CXX_TRUE@ $(am__DEPENDENCIES_3) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -282,7 +288,8 @@ SOURCES = $(aio01_SOURCES) $(dir01_SOURCES) $(fio01_SOURCES) \ $(pio01_SOURCES) $(rwl01_SOURCES) $(sck01_SOURCES) \ $(sio01_SOURCES) $(sio02_SOURCES) $(sio03_SOURCES) \ $(spl01_SOURCES) $(spl02_SOURCES) $(task01_SOURCES) \ - $(tcpsvr01_SOURCES) $(thr01_SOURCES) $(thr02_SOURCES) + $(tcpsvr01_SOURCES) $(thr01_SOURCES) $(thr02_SOURCES) \ + $(thr03_SOURCES) DIST_SOURCES = $(aio01_SOURCES) $(dir01_SOURCES) $(fio01_SOURCES) \ $(fio02_SOURCES) $(fs01_SOURCES) $(fs02_SOURCES) \ $(fs03_SOURCES) $(glob01_SOURCES) $(log01_SOURCES) \ @@ -291,7 +298,7 @@ DIST_SOURCES = $(aio01_SOURCES) $(dir01_SOURCES) $(fio01_SOURCES) \ $(sio01_SOURCES) $(sio02_SOURCES) $(sio03_SOURCES) \ $(spl01_SOURCES) $(am__spl02_SOURCES_DIST) $(task01_SOURCES) \ $(am__tcpsvr01_SOURCES_DIST) $(thr01_SOURCES) \ - $(am__thr02_SOURCES_DIST) + $(am__thr02_SOURCES_DIST) $(am__thr03_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -517,10 +524,12 @@ thr01_SOURCES = thr01.c @ENABLE_CXX_TRUE@spl02_SOURCES = spl02.cpp @ENABLE_CXX_TRUE@tcpsvr01_SOURCES = tcpsvr01.cpp @ENABLE_CXX_TRUE@thr02_SOURCES = thr02.cpp +@ENABLE_CXX_TRUE@thr03_SOURCES = thr03.cpp @ENABLE_CXX_TRUE@sck01_LDADD = $(CXXLIB) $(LDADD) @ENABLE_CXX_TRUE@spl02_LDADD = $(CXXLIB) $(LDADD) @ENABLE_CXX_TRUE@tcpsvr01_LDADD = $(CXXLIB) $(LDADD) @ENABLE_CXX_TRUE@thr02_LDADD = $(CXXLIB) $(LDADD) +@ENABLE_CXX_TRUE@thr03_LDADD = $(CXXLIB) $(LDADD) all: all-am .SUFFIXES: @@ -700,6 +709,10 @@ thr02$(EXEEXT): $(thr02_OBJECTS) $(thr02_DEPENDENCIES) $(EXTRA_thr02_DEPENDENCIE @rm -f thr02$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(thr02_OBJECTS) $(thr02_LDADD) $(LIBS) +thr03$(EXEEXT): $(thr03_OBJECTS) $(thr03_DEPENDENCIES) $(EXTRA_thr03_DEPENDENCIES) + @rm -f thr03$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(thr03_OBJECTS) $(thr03_LDADD) $(LIBS) + mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -730,6 +743,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcpsvr01.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thr01.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thr02.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thr03.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/qse/samples/si/thr03.cpp b/qse/samples/si/thr03.cpp new file mode 100644 index 00000000..3b095dfe --- /dev/null +++ b/qse/samples/si/thr03.cpp @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include + + +#include +#if defined(_WIN32) +# include +#endif + +#include +#include +#include + +static int g_stopreq = 0; +static qse_mtx_t* g_prmtx = QSE_NULL; + +QSE::HeapMmgr g_heap_mmgr (QSE::Mmgr::getDFL(), 30000); + +struct rq_data_t +{ + rq_data_t(): stop(0) {} + int stop; + QSE::Mutex mtx; + QSE::Condition cnd; +}; + +class Waiter +{ +public: + int operator() (QSE::Thread* thr) + { + int i = 0; + rq_data_t* rqdata = (rq_data_t*)thr->getContext(); + + while (1) + { + rqdata->mtx.lock (); + if (rqdata->stop) + { + rqdata->mtx.unlock (); + break; + } + rqdata->cnd.wait(rqdata->mtx); + rqdata->mtx.unlock (); + + qse_mtx_lock (g_prmtx, QSE_NULL); + qse_printf (QSE_T("[%p] -> loop %d\n"), this, i); + qse_mtx_unlock (g_prmtx); + i++; + } + + qse_mtx_lock (g_prmtx, QSE_NULL); + qse_printf (QSE_T("[%p] -> exiting\n"), this); + qse_mtx_unlock (g_prmtx); + return i; + } +}; + +static int test1 (void) +{ + g_prmtx = qse_mtx_open (QSE_MMGR_GETDFL(), 0); + + rq_data_t rqdata; + QSE::ThreadF thr[3]; + + for (int i = 0; i < 3; i++) + { + thr[i].setStackSize (64000); + thr[i].setContext (&rqdata); + if (thr[i].start(QSE::Thread::SIGNALS_BLOCKED) <= -1) + { + qse_printf (QSE_T("cannot start thread%d\n"), i); + return -1; + } + } + + while (1) + { + if (g_stopreq) + { + qse_mtx_lock (g_prmtx, QSE_NULL); + qse_printf (QSE_T("broadcasting stop ---> 1\n")); + qse_mtx_unlock (g_prmtx); + + rqdata.mtx.lock (); + rqdata.stop = 1; + rqdata.mtx.unlock (); + rqdata.cnd.broadcast (); + } + + int nterm = 0; + for (int i = 0; i < 3; i++) + { + if (thr[i].getState() == QSE::Thread::TERMINATED) nterm++; + } + if (nterm == 3) break; + + qse_mtx_lock (g_prmtx, QSE_NULL); + qse_printf (QSE_T("signalling ....(nterm = %d)\n"), nterm); + qse_mtx_unlock (g_prmtx); + + rqdata.cnd.signal (); + sleep (1); + } + + + for (int i = 0; i < 3; i++) + { + thr[i].join(); + } + + for (int i = 0; i < 3; i++) + { + qse_printf (QSE_T("thread%d ended with retcode %d\n"), i, thr[i].getReturnCode()); + } + + qse_mtx_close (g_prmtx); + return 0; +} + + +static void handle_sigint (int sig, siginfo_t* siginfo, void* ctx) +{ + g_stopreq = 1; +} + +static void set_signal (int sig, void(*handler)(int, siginfo_t*, void*)) +{ + struct sigaction sa; + + memset (&sa, 0, sizeof(sa)); + /*sa.sa_handler = handler;*/ + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = handler; + sigemptyset (&sa.sa_mask); + + sigaction (sig, &sa, NULL); +} + +static void set_signal_to_default (int sig) +{ + struct sigaction sa; + + memset (&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (sig, &sa, NULL); +} + +int main () +{ +#if defined(_WIN32) + char locale[100]; + UINT codepage = GetConsoleOutputCP(); + if (codepage == CP_UTF8) + { + /*SetConsoleOUtputCP (CP_UTF8);*/ + qse_setdflcmgrbyid (QSE_CMGR_UTF8); + } + else + { + sprintf (locale, ".%u", (unsigned int)codepage); + setlocale (LC_ALL, locale); + /*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ + } +#else + setlocale (LC_ALL, ""); + /*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ +#endif + + set_signal (SIGINT, handle_sigint); + + qse_open_stdsios (); + test1(); + qse_close_stdsios (); + + set_signal_to_default (SIGINT); + + return 0; +}