質問
使用する古いコードがいくつかあります qsort
MFCを並べ替えます CArray
構造物ですが、時折クラッシュが見られます 五月 複数のスレッドを呼び出します qsort
同時に。私が使用しているコードは次のように見えます:
struct Foo
{
CString str;
time_t t;
Foo(LPCTSTR lpsz, time_t ti) : str(lpsz), t(ti)
{
}
};
class Sorter()
{
public:
static void DoSort();
static int __cdecl SortProc(const void* elem1, const void* elem2);
};
...
void Sorter::DoSort()
{
CArray<Foo*, Foo*> data;
for (int i = 0; i < 100; i++)
{
Foo* foo = new Foo("some string", 12345678);
data.Add(foo);
}
qsort(data.GetData(), data.GetCount(), sizeof(Foo*), SortProc);
...
}
int __cdecl SortProc(const void* elem1, const void* elem2)
{
Foo* foo1 = (Foo*)elem1;
Foo* foo2 = (Foo*)elem2;
// 0xC0000005: Access violation reading location blah here
return (int)(foo1->t - foo2->t);
}
...
Sorter::DoSort();
私は使用するこの恐ろしいコードをリファクタリングしようとしています std::sort
代わりに、上記が実際に安全でないかどうか疑問に思いましたか?
編集: Sorter::DoSort
実際には静的関数ですが、静的変数自体は使用しません。
edit2:sortproc関数は、実際のコードと一致するように変更されています。
解決
あなたの問題は必ずしもスレッド・サフティとは何の関係もありません。
ソートコールバック関数は、アイテム自体ではなく、各アイテムへのポインターを取り入れます。あなたが並べ替えているので Foo*
あなたが実際にやりたいのは、パラメーターに次のようにアクセスすることです Foo**
, 、 このような:
int __cdecl SortProc(const void* elem1, const void* elem2)
{
Foo* foo1 = *(Foo**)elem1;
Foo* foo2 = *(Foo**)elem2;
if(foo1->t < foo2->t) return -1;
else if (foo1->t > foo2->t) return 1;
else return 0;
}
他のヒント
sortprocは正しい結果を返していないため、これはおそらく、データが並べ替えた後にデータがソートされたと仮定して、メモリの腐敗につながる可能性があります。 QSORTを整理しようとするので、QSORTを汚職に導くことさえできますが、もちろん実装によって異なります。
QSORTの比較関数は、最初のオブジェクトが2番目のオブジェクトよりも少なく、等しい場合はゼロ、そうでない場合は正のオブジェクトの比較関数がネガティブを返す必要があります。現在のコードは0または1を返すだけで、ネガティブを返す必要がある場合に1を返します。
int __cdecl Sorter::SortProc(const void* ap, const void* bp) {
Foo const& a = *(Foo const*)ap;
Foo const& b = *(Foo const*)bp;
if (a.t == b.t) return 0;
return (a.t < b.t) ? -1 : 1;
}
C ++は、スレッドの安全性について実際に保証しません。あなたが言うことができることは、複数の読者またはデータ構造の単一のライターのいずれかが大丈夫だということです。読者と作家の任意の組み合わせであり、アクセスを何らかの形でシリアル化する必要があります。
あなたがあなたの質問にタグを付けたので MFC
タグプロジェクト設定でマルチスレッドランタイムライブラリを選択する必要があると思います。
現在、コードはスレッドセーフですが、役に立たないです。なぜなら、ドゾートメソッドはローカル変数のみを使用しており、何も返さないためです。ソートしているデータがSorterのメンバーである場合、複数のスレッドから関数を呼び出すことは安全ではありません。 Gerenalで、読んでください 再発, 、これはあなたがあなたが何に注意する必要があるかについてあなたにアイデアを与えるかもしれません。
スレッドを安全にするのは、オブジェクトがスレッドセーフであるかどうか、たとえばQSORTスレッドセーフを作成するために、オブジェクトに出入りするものがすべてスレッド安全であることを確認する必要があります。
Pthreads Manページには、スレッドセーフである必要がない標準関数がリストされています。 QSORTはその中にいないので、スレッドセーフである必要があります Posixで.
http://www.kernel.org/doc/man-pages/online/pages/man7/pthreads.7.html
ただし、Windowsの同等のリストが見つかりません。これは、実際にはあなたの質問に対する答えではありません。それが違うなら、私は少し驚くでしょう。
ただし、この文脈で「スレッドセーフ」が何を意味するかに注意してください。つまり、異なる配列で同じ関数を同時に呼び出すことができることを意味します。それは、QSORTを介した同じデータへの同時アクセスが安全であることを意味しません(そうではありません)。
警告の言葉として、あなたは見つけるかもしれません std::sort
速くはありません qsort
. 。あなたがそれを見つけたなら、それを試してください std::stable_sort
.
私はかつてコードに基づいてBWTコンプレッサーを書きましたDobbs博士に私のMark Nelsonを提示しました、そして、私がそれをクラスに変えたとき、私はその通常のことを見つけました sort
ずっと遅かった。 stable_sort
速度の問題を修正しました。