Zrobiłem sobie małą nakładkę na pthreads:
//posix_thread.h
#ifndef POSIXTHREAD_H
#define POSIXTHREAD_H
#include <pthread.h>
#define FRIEND_WITH_F friend void *functionOfPosixThread(void *pointerToThreadObject) ;
void *functionOfPosixThread(void *pointerToThreadObject) ;
class PosixThread
{
FRIEND_WITH_F
public:
PosixThread();
virtual ~PosixThread();
void Start();
void Stop();
inline void PauseOn()
{
paused=1 ;
}
inline void PauseOff()
{
paused=0 ;
}
inline void SetDelay(unsigned int delay)
{
this->delay = delay;
}
inline unsigned int GetDelay() const
{
return delay;
}
protected:
virtual void Work()=0 ;
private:
unsigned int delay ;
pthread_t thread ;
int resultOfThreadOperations ;
volatile bool working ;
volatile bool paused ;
};
#endif // POSIXTHREAD_H
//posix_thread.cpp
#include "posix_thread.h"
#include <unistd.h>
PosixThread::PosixThread()
{
delay = 1000 ;
resultOfThreadOperations = 0 ;
working = 0 ;
paused = 0 ;
}
PosixThread::~PosixThread()
{
}
void PosixThread::Start()
{
resultOfThreadOperations = pthread_create( &thread, NULL, functionOfPosixThread, (void*)this);
}
void PosixThread::Stop()
{
if((!working) || (resultOfThreadOperations!=0))
{
return;
}
paused=0;
working=0;
resultOfThreadOperations = pthread_join(thread, NULL);
}
void *functionOfPosixThread(void* pointerToThreadObject)
{
PosixThread* thread = (PosixThread*)pointerToThreadObject ;
thread->working=1 ;
thread->paused=0;
while(thread->working)
{
if(thread->paused)
{
continue ;
}
thread->Work() ;
usleep(thread->delay) ;
}
pthread_exit(0);
}
Tutaj konkretna testowa implementacja:
//main.cpp
#include <iostream>
#include <gtest/gtest.h>
#include "posix_thread_test.h"
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
//posix_thread_test.h"
#ifndef POSIXTHREADTEST_H
#define POSIXTHREADTEST_H
#include <gtest/gtest.h>
#include "../Server/posix_thread.h"
#include <string>
namespace
{
class PosixThreadTest : public ::testing::Test
{
protected:
PosixThreadTest(){};
virtual ~PosixThreadTest(){};
virtual void SetUp(){} ;
virtual void TearDown(){} ;
};
}
class PosixThread4ITest : public PosixThread
{
FRIEND_WITH_F
public:
PosixThread4ITest(std::string nameOfThread) : PosixThread(), name(nameOfThread)
{
counter=0;
std::cout<<"PosixThread4ITest "<<name<<" Constructor\n" ;
}
virtual ~PosixThread4ITest()
{
std::cout<<"PosixThread4ITest "<<name<<" Destructor\n" ;
}
protected:
virtual void Work()
{
std::cout<<"PosixThread4ITest "<<name<<" working: #"<<counter++<<"\n" ;
}
private:
long long unsigned int counter ;
const std::string name ;
};
#endif // POSIXTHREADTEST_H
//posix_thread_test.cpp
#include "posix_thread_test.h"
TEST(PosixThreadTest, ThreeThreads)
{
PosixThread4ITest p1("thread1") ;
PosixThread4ITest p2("thread2") ;
p1.SetDelay(500000) ;
p2.SetDelay(800000) ;
std::cout<<"Start threads.\n";
p1.Start() ;
p2.Start() ;
std::cout<<"Started.\n";
std::cout<<"Waiting for 5 secs.\n" ;
sleep(5) ;
std::cout<<"Stop.\n" ;
p1.Stop() ;
p2.Stop() ;
std::cout<<"Stopped.\n" ;
std::cout<<"Done.\n" ;
}
Wszystko działa, ale gdy chcę sprawdzić valgrindem czy są wycieki pamięci, zawsze, niezależnie od ilości wątków, wskazuje mi, że 28 bajtów jest "still reachable":
valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./Tests
==4100== Memcheck, a memory error detector
==4100== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==4100== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==4100== Command: ./IntegrationTests
==4100==
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from PosixThreadTest
[ RUN ] PosixThreadTest.ThreeThreads
PosixThread4ITest thread1 Constructor
PosixThread4ITest thread2 Constructor
Start threads.
PosixThread4ITest thread1 working: #0
PosixThread4ITest thread2 working: #0
Started.
Waiting for 5 secs.
PosixThread4ITest thread1 working: #1
PosixThread4ITest thread2 working: #1
PosixThread4ITest thread1 working: #2
PosixThread4ITest thread1 working: #3
PosixThread4ITest thread2 working: #2
PosixThread4ITest thread1 working: #4
PosixThread4ITest thread2 working: #3
PosixThread4ITest thread1 working: #5
PosixThread4ITest thread1 working: #6
PosixThread4ITest thread2 working: #4
PosixThread4ITest thread1 working: #7
PosixThread4ITest thread2 working: #5
PosixThread4ITest thread1 working: #8
PosixThread4ITest thread1 working: #9
PosixThread4ITest thread2 working: #6
PosixThread4ITest thread1 working: #10
Stop.
PosixThread4ITest thread2 working: #7
Stopped.
Done.
PosixThread4ITest thread2 Destructor
PosixThread4ITest thread1 Destructor
[ OK ] PosixThreadTest.ThreeThreads (6545 ms)
[----------] 1 test from PosixThreadTest (6580 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (6675 ms total)
[ PASSED ] 1 test.
==4100==
==4100== HEAP SUMMARY:
==4100== in use at exit: 28 bytes in 1 blocks
==4100== total heap usage: 288 allocs, 287 frees, 56,272 bytes allocated
==4100==
==4100== 28 bytes in 1 blocks are still reachable in loss record 1 of 1
==4100== at 0x4024F20: malloc (vg_replace_malloc.c:236)
==4100== by 0x400C37E: _dl_map_object_deps (dl-deps.c:506)
==4100== by 0x4011BA0: dl_open_worker (dl-open.c:262)
==4100== by 0x400D7E5: _dl_catch_error (dl-error.c:178)
==4100== by 0x40115E5: _dl_open (dl-open.c:554)
==4100== by 0x429E4A1: do_dlopen (dl-libc.c:86)
==4100== by 0x400D7E5: _dl_catch_error (dl-error.c:178)
==4100== by 0x429E5A0: dlerror_run (dl-libc.c:47)
==4100== by 0x429E6BA: __libc_dlopen_mode (dl-libc.c:160)
==4100== by 0x4053B46: pthread_cancel_init (unwind-forcedunwind.c:53)
==4100== by 0x4053CBC: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)
==4100== by 0x4051787: __pthread_unwind (unwind.c:130)
==4100==
==4100== LEAK SUMMARY:
==4100== definitely lost: 0 bytes in 0 blocks
==4100== indirectly lost: 0 bytes in 0 blocks
==4100== possibly lost: 0 bytes in 0 blocks
==4100== still reachable: 28 bytes in 1 blocks
==4100== suppressed: 0 bytes in 0 blocks
==4100==
==4100== For counts of detected and suppressed errors, rerun with: -v
==4100== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 20 from 7)
Niby nie ma wycieków, tylko to "still reachable", ale chciałbym mieć wszystko na czysto. Czy ktoś jest w stanie powiedzieć w którym miejscu kodu mogę mieć błąd?
Komentowałem kawałkami kod i te "stiil reachable" bajty występują tylko wtedy, gdy się wywoła funkcję Start() - czyli gdzieś tam musi być zły kod.