May 4, 2012

GSDeveloper GSDeveloper
Lab Rat
4 posts

Kill QThreadPool

 

Salve a tutti,

Scrivo per la prima volta in questo forum.
Ho un problema utilizzando QtConcurrent::run. In pratica sto provando a vedere quanto possa essere robusto un programma, utilizzando piu’ thread con QtConcurrent, per poter scrivere su un Database in modo non bloccante.
Il tutto funziona perfettamente nel metodo QtConcurrent::run eseguo una mia procedura di connessione verso un Database SQL Express con ODBC. Per provare ho inserito una sleep all’interno della procedura per simulare una query piu’ lunga del necessario. Ho scoperto che se sono in questa sleep, all’interno del metdo QtConcurrent::run, e provo a chiudere il programma succede che viene chiuso tutto (finestre, thread generati da me ecc.) tranne i Thread generati dal QtConcurrent. Il programma quindi rimane bloccato e non termina subito.
Leggendo ho scoperto che QtConcurrent fa uso del QThreadPool, pero’ non ho trovato nulla per terminare in modo istantaneo questi Thread. Se quindi, in un metodo di QtConcurrent::run, succede qualcosa di inaspettato che prolunga l’esecuzione della funzione, come posso terminare quel Thread istantaneamente?

Grazie in anticipo.

2 replies

May 7, 2012

cristiano cristiano
Lab Rat
2 posts

Ciao,

hai provato ad usare la classe QFuture?
Aiuterebbe vedere il tuo codice per capire meglio in che situazione ti trovi, ma QFuture dovrebbe consentirti di interrompere una elaborazione in corso lanciata con QtConcurrent::run.
http://qt-project.org/doc/qt-4.8/qfuture.html

Spero ti sia di aiuto.
Saluti,
-Cristiano

May 7, 2012

GSDeveloper GSDeveloper
Lab Rat
4 posts

Grazie per l’aiuto. Non ho ancora provato con QFuture perche’ ho visto che c’e’ scritto nel Help:
“… Be aware that not all asynchronous computations can be canceled. For example, the future returned by QtConcurrent::run() cannot be canceled; but the future returned by QtConcurrent::mappedReduced() can…”.

Sembra che le elaborazioni lanciate con QtConcurrent non si puo’ usare il metodo “QFuture::cancel()”.
Il codice e’ il seguente:

  • Con questo metodo lancio i vari “QtConcurrent::run”:

  1. void DBManagerObj::NewOptSlot(const NewOptDataDB &tNewOptData)
  2. {
  3.  if(DBManagerThrStatus::RUN_STS == _tThrStatus.iStatus)
  4.  {
  5.   DBIntStatusFut *ptFut = new DBIntStatusFut(QtConcurrent::run(this,
  6.    &DBManagerObj::NewOptExecThr,
  7.    tNewOptData));
  8.   poco_check_ptr(ptFut);
  9.  
  10.   _rgptResFuture.append(ptFut);
  11.  }
  12. }

  • Questo e’ il metodo che esegue le operazioni di scrittura su Database (da notare che non uso le funzionalita’ dell Qt SQL, ma utilizzo in questo caso le POCO C++ library, perche’ hanno la gestione integrata del “Session Pool” e poi perche’ hanno altre Feature che ho gia’ utilizzate in passato)

  1. DBManagerObj::DBIntStatus DBManagerObj::NewOptExecThr(const NewOptDataDB &tNewOptData)
  2. {
  3.  if(!_ptSessPool)
  4.  {
  5.   poco_warning(_tLog,
  6.    "DBManagerObj: WARNING: no Session Pool!");
  7.  
  8.   return DBManagerObj::DBIntStatus(-1);
  9.  }
  10.  
  11.  QElapsedTimer tTimer;
  12.  
  13.  tTimer.start();
  14.  try
  15.  {
  16.   Poco::Data::Session tSess(_ptSessPool->get());
  17.  
  18.   tSess << "INSERT INTO TNewOptData (BTCTL, ID, BTC1m, Vel, DLTLDist, DLPos) "
  19.    "VALUES(?,?,?,?,?,?)",
  20.    Poco::Data::use(tNewOptData.i32BTCTL),
  21.    Poco::Data::use(tNewOptData.i32ID),
  22.    Poco::Data::use(tNewOptData.BTC1m),
  23.    Poco::Data::use(tNewOptData.Vel),
  24.    Poco::Data::use(tNewOptData.DLTLDist),
  25.    Poco::Data::use(tNewOptData.DLPos),
  26.    Poco::Data::now;
  27.  }
  28.  catch(Poco::Data::ODBC::ODBCException &tExc)
  29.  {
  30.   std::string strTemp = "DBManagerObj: Insert Data Failed!: ";
  31.  
  32.   strTemp += tExc.className();
  33.   strTemp += " ";
  34.   strTemp += tExc.displayText();
  35.   poco_warning(_tLog,
  36.    strTemp);
  37.  }
  38.  
  39.  return DBManagerObj::DBIntStatus(1,
  40.   tTimer.elapsed());
  41. }

Il problema secondo me e’ che se nel secondo metodo, per qualche motivo l’elaborazione si dovesse prolungare, non ho modo di concludere l’operazione se l’utente chiede di arrestare il programma. Mettendo infatti una Sleep (tanto per simulare un “Long Run”), all’interno del secondo metodo, il programma resta piantato fintatnto che il QtConcurrent::run non finisce l’esecuzione.

Saluti
Giulio

 
  ‹‹ Ministro qt      Copiright ››

You must log in to post a reply. Not a member yet? Register here!