Я использую приведенный ниже код для создания потоков и добавления их в пул потоков. Потоки загружаются нормально, и каждый из них выполняет простую процедуру циклизации до тех пор, пока основной поток не вызовет ResetWorkerThreads второй раз и не уничтожит подпионы. Подводные потоки прерываются, однако основной поток также выходит. На консоль нет ошибок. Я не могу оборачивать вокруг себя, поскольку он не имеет никакого исключения, и основной поток не был добавлен в пул потоков vecThreads. Также во второй раз, когда эта функция является все, "Все потоки убиты" не выводится, как будто она никогда не достигает этой точки.
std::string strPreviousSettings = "0";
std::string strPreviousAgentSettings = "0";
bool boolResetWorkers;
std::string strIP;
std::string strMACAddress;
boost::thread_group vecThreads;
std::string GetIP()
{
std::string strIP;
try
{
using namespace boost::network;
std::string strRequest;
http::client client;
http::client::request request("http://test.com/ip.php");
http::client::response response = client.get(request);
strIP = body(response);
}
catch(...)
{
cout << "GetLocalIP - Error: " << endl;
}
return strIP;
}
std::string getMacAddress()
{
std::string strMACAddress = GetFileContents("/sys/class/net/eth0/address");
boost::replace_all(strMACAddress, ":", "");
boost::replace_all(strMACAddress, "\n", "");
return strMACAddress;
}
void ThreadSettingsWorker()
{
int x = 1;
strIP = GetIP();
strMACAddress = getMacAddress();
do {
CheckEventSettings();
CheckAgentSettings();
if(boolResetWorkers==true)
{
ResetWorkerThreads();
} else {
boost::this_thread::sleep(boost::posix_time::milliseconds(3000));
}
} while ( x != 0 );
}
void ResetWorkerThreads()
{
cout << "Resetting Workers Threads\n";
boolResetWorkers = false;
int intWorkerCount = 10; //Spawn 10 workers
int X = 0;
int intI = 1;
cout << "Kill All Threads\n";
try
{
vecThreads.interrupt_all();
}
catch(...)
{
//std::cerr << "Kill All Threads: " << std::endl;
}
cout << "All Threads Killed\n";
for (int i = 0; i < intWorkerCount; ++i)
{
cout << "Starting Worker: " << (i + 1) << "\n";
boost::thread tWorker(&ThreadWorker, (i + 1));
vecThreads.add_thread(&tWorker);
}
}
void TestRequest()
{
try
{
using namespace boost::network;
std::stringstream ss;
http::client client;
ss << "http://test.com/sadasdasd.html";
http::client::request request(ss.str());
http::client::response response = client.get(request);
std::string strOutput = body(response);
cout << "Test Request Out: " << strOutput << "\n";
}
catch(...)
{
cout << "TestRequest - Error: " << endl;
return;
}
}
void ThreadWorker(int intThread)
{
try
{
int X = 0;
do {
cout << "Thread " << intThread << "\n";
TestRequest();
} while ( X != 55 );
}
catch(...)
{
}
}
void CheckEventSettings()
{
try
{
using namespace boost::network;
std::string strRequest;
http::client client;
http::client::request request("http://test.com/events.php");
http::client::response response = client.get(request);
std::string strOutput = body(response);
if(strPreviousSettings==strOutput)
{
cout << "No Event Settings Changes\n";
} else {
cout << "Applying New Event Settings\n";
strPreviousSettings = strOutput;
std::string strDividerLine = "<br>";
std::string strDividerField = "<field>";
std::vector<std::string> vEvents;
vEvents = EasySplit(strOutput, strDividerLine);
for(std::vector<std::string>::const_iterator iEvent = vEvents.begin(); iEvent != vEvents.end() - 1; ++iEvent) {
}
}
}
catch(...)
{
cout << "CheckEventSettings - Error: " << endl;
return;
}
}
void CheckAgentSettings()
{
try
{
using namespace boost::network;
std::stringstream ss;
http::client client;
ss << "http://test.com/checksettings.php";
http::client::request request(ss.str());
http::client::response response = client.get(request);
std::string strOutput = body(response);
if(strPreviousAgentSettings==strOutput)
{
cout << "No Agent Settings Changes\n";
} else {
cout << "Applying New Agent Settings\n";
strPreviousAgentSettings = strOutput;
boolResetWorkers = true;
}
}
catch(...)
{
cout << "CheckAgentSettings - Error: " << endl;
return;
}
}
int main()
{
// Start thread
boost::thread tCheckSettings(&ThreadSettingsWorker);
// Ask thread to stop
//tCheckSettings.interrupt();
// Join - wait when thread actually exits
tCheckSettings.join();
return 0;
}
У вас есть ошибка здесь:
boost::thread tWorker(&ThreadWorker, (i + 1));
vecThreads.add_thread(&tWorker);
Вы создаете локальный объект tWorker
который удаляется сразу после вызова add_thread()
. Так vecThreads содержит висячие указатели на thread
с. Когда вы вызываете vecThreads.interrupt_all()
вы получаете неопределенное поведение, потому что vecThreads
пытается получить доступ к удаленным объектам thread
и я полагаю, что ваша программа просто завершается из-за нарушения доступа или чего-то еще.
Вы должны изменить свой код на что-то вроде этого:
boost::thread* ptWorker = new boost::thread(&ThreadWorker, (i + 1));
vecThreads.add_thread(ptWorker);
Обратите внимание, что вам не нужно delete
те объекты thread
самостоятельно. thread_group
delete
их самостоятельно.
Сложение:
Проблема с terminate()
может быть вызвана деструктором http::client
бросающим исключение. Попробуйте это, чтобы устранить эту проблему в TestRequest()
:
try{
http::client client;
try{
// other code
}
catch (){}
}
catch(){}
Также я предлагаю сбросить vecThreads
после interrupt_all()
. Например, вы можете определить его как boost::scoped_ptr
а затем сделать pvecThreads.reset(new boost::thread_group())
после вызова interrupt_all()
.
В настоящее время прерванные потоки по-прежнему остаются в thread_group
после прерывания, а затем вы пытаетесь interrupt
их снова вместе с новыми потоками, добавленными в thread_group
позже в ResetWorkerThreads()
.
http::client client;
изнутри блока try
. Таким образом, код должен быть http::client client; try {...}
вместо try{ http::client client; ...}
Внутри ResetWorkerThreads У вас есть:
for (int i = 0; i < intWorkerCount; ++i)
{
cout << "Starting Worker: " << (i + 1) << "\n";
// One issue is here, don't create a thread on the stack
// and pass it to the thread group use new instead!
boost::thread tWorker(&ThreadWorker, (i + 1));
vecThreads.add_thread(&tWorker);
}
Вы добавляете поток, созданный в стек, к группе потоков. Как только вы перейдете через цикл, чтобы потоковая память была недействительной. Вам нужно будет создать new
поток и передать этот указатель на add_thread.