私は現在Linux上のC++でWebクローラ/スパイダーを作成していますが、データベースの更新にいくつか問題があります。私は公平に新しいC/C++、ちょうどFYIです。glibcのメモリ破損libmysqlcppconnでの準備文
データベースの更新は別々のスレッド(pthreadsを使用)で実行されますが、main()で実行すると同じ問題が存在するため、スレッドの内容を何らかの原因として破棄します。
データベースAPIにlibmysqlcppconnを使用しています。
-O2 -Wall -pedanticを使用してgcc 4.4.3(Ubuntu 4.4.3-4ubuntu5.1)でコンパイルしていて、きれいにコンパイルしています。
しかし、以下の関数commitChangesToDatabase()が呼び出されると、std :: map(url_queue)から項目を取り出し、std :: vector(スクロールバー)にスローし、元のstdからその項目を消去します。 :: mapを実行し、std :: vectorを繰り返し処理して、ベクトルの各項目のMySQLプリペアドステートメントを実行します。ここでそれが難しいところです。ランダム
これは、次のいずれか任意のエラー出力なし
- クラッシュ(なしセグメンテーション違反、無スタックトレース、ノー何も)検出されたglibcのメモリの破損と
- クラッシュ(ここでは、出力参照:http://pastie.org/private/wlkuorivq5tptlcr7ojg)を
- レポートMySQLサーバが離れている(例外がキャッチされている)が、試行し続ける(クラッシュしない)
私は単純なexe cuteUpdate()ですが、無駄です。 私は項目を選ぶことでそのステップを削除しようとしましたが、url_queueの最初のループで更新する項目が見つかるたびに更新を実行します。
このアプリケーションの他の機能は、プリペアドステートメント(別のUPDATE)も使用しており、正常に動作します。これらの関数は別々のスレッドでも実行されます。
私はvalgrindを使ってアプリケーションを実行しましたが、率直に言って出力の大部分を理解していないので、それほど助けにならないでしょう - しかし、誰かが出力を望むなら、実行するオプションを教えてください私はそれを提供します。
私はここから進める方法がありません。誰が何が間違っているかの手掛かりを持っていますか?
struct queue_item_t {
int id;
int sites_id;
int priority;
int depth;
int handler;
int state; // 0 = Pending, 1 = Working, 2 = Completed, 3 = Checked
double time_allowed_crawl;
bool status;
bool was_redirected;
double time;
double time_end;
double time_curl;
double size;
std::string hash;
std::string url;
std::string file;
std::string host;
};
void commitChangesToDatabase()
{
map< string, queue_item_t >::iterator it, end;
sql::PreparedStatement *pstmt;
int i = 0;
if (!url_queue.size()) {
return;
}
pthread_mutex_lock(&dbCommitMutex);
pthread_mutex_lock(&itemMutex);
cout << "commitChangesToDatabase()" << endl;
pstmt = dbPrepareStatement("UPDATE crawler_queue SET process_hash = NULL, date_crawled = NOW(), url = ?, hash = ? WHERE id = ?");
for (it = url_queue.begin(); it != url_queue.end();)
{
if (it->second.state == 2)
{
pstmt->setString(1, it->second.url);
pstmt->setString(2, it->second.hash);
pstmt->setInt(3, it->second.id);
try {
pstmt->executeUpdate();
++i;
} catch (sql::SQLException &e) {
cerr << "# ERR: SQLException in " << __FILE__;
cerr << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
cerr << "# ERR: " << e.what();
cerr << " (MySQL error code: " << e.getErrorCode();
cerr << ", SQLState: " << e.getSQLState() << ")" << endl;
}
url_queue.erase(it++);
}
else {
++it;
}
}
delete pstmt;
cout << "~commitChangesToDatabase()" << endl;
pthread_mutex_unlock(&itemMutex);
pthread_mutex_unlock(&dbCommitMutex);
}
// this function is defined in another file but is written here just to show the contents of it
sql::PreparedStatement *dbPrepareStatement(const std::string &query)
{
return con->prepareStatement(query);
}
編集:
一部は、しかし、私はそれを除外しますが、データベース上で動作し、すべてではなく、反復をコメントアウトしている、問題はurl_queueコレクションを反復処理であると信じているようです。さらに、ここでの反復は、以下に示すように、マップからアイテムを取り出し、ベクトルをスローし、マップから消去し、プログラムのその部分がうまく動作する、元の単純化された(ただし動作する)バージョンです。は、データベースが使用されるたびにクラッシュします。
for (it = url_queue.begin(); it != url_queue.end();)
{
if (it->second.state == 2)
{
update_item.type = (!it->second.was_redirected ? 1 : 2);
update_item.item = it->second;
updates.push_back(update_item);
url_queue.erase(it++);
}
else {
++it;
}
}
編集2:valgrind --leak-check=yes
から
出力:http://pastie.org/private/2ypk0bmawwsqva3ikfazw
あなたの質問に 'queue_item_t'の宣言を追加できますか? –
また、反復処理中のコレクションからアイテムを消去しないでください。イテレータを無効にすることがあります。また、イテレータを常に2回増やします。それは意図的な2回目の項目へのジャンプですか? –
コレクションから消去する方法を見つけました。ここで繰り返しているStackOverflowでは、反復ごとにコレクションの.begin()と.end()を評価することを提案しています。申し訳ありませんが、二重増加は、問題に影響しなかった間違いでした。++はfor(;;)内にあるべきではありません。 –