qsort线程安全吗?

时间:2010-03-11 11:32:09

标签: c++ mfc qsort

我有一些旧的代码使用qsort对结构的MFC CArray进行排序,但是我发现可能偶尔崩溃到多个线程调用{{1} }} 同时。我使用的代码看起来像这样:

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实际上是一个静态函数,但本身不使用静态变量。

EDIT2:SortProc功能已更改为与实际代码匹配。

8 个答案:

答案 0 :(得分:5)

您的问题不一定与线程安全有关。

排序回调函数接收指向每个项目的指针,而不是项目本身。由于您要对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;
}

答案 1 :(得分:4)

您的SortProc没有返回正确的结果,这可能会导致内存损坏,假设数据在排序完成后排序。你甚至可以在尝试排序时将qsort引入腐败,但这当然因实现而异。

如果第一个对象小于第二个对象,qsort的比较函数必须返回负数,如果它们相等则返回零,否则返回正数。您当前的代码只返回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;
}

答案 2 :(得分:1)

C ++并没有真正保证线程安全。你可以说最多的是,无论是多个读者还是单个写入者都可以使用数据结构。读者和作者的任何组合,你需要以某种方式序列化访问。

答案 3 :(得分:1)

由于您使用MFC标记标记了您的问题,我认为您应该在项目设置中选择多线程运行时库。

答案 4 :(得分:0)

现在,您的代码是线程安全的,但没用,因为DoSort方法只使用局部变量,甚至不返回任何内容。如果要排序的数据是Sorter的成员,那么从多个线程调用该函数是不安全的。在gerenal中,请阅读reentrancy,这可能会让您了解需要注意的事项。

答案 5 :(得分:0)

使线程安全的是,无论你的对象是否是线程安全的,例如为了使qsort线程安全,你必须确保任何对该对象进行写入或读取的内容都是线程安全的。

答案 6 :(得分:0)

pthreads手册页列出了不需要线程安全的标准函数。 qsort不在其中,因此需要在POSIX 中是线程安全的

http://www.kernel.org/doc/man-pages/online/pages/man7/pthreads.7.html

我找不到Windows的等效列表,所以这不是你问题的真正答案。如果它不同我会有点惊讶。

请注意,在这种情况下,“线程安全”意味着什么。这意味着您可以在不同的阵列上同时调用相同的函数 - 这并不意味着通过qsort并发访问相同的数据是安全的(它不是)。

答案 7 :(得分:-2)

作为警告,您可能会发现std::sort没有qsort那么快。如果您确实找到了std::stable_sort

我曾经根据Dobbs博士的Mark Nelson写的代码编写了一个BWT压缩器,当我把它变成课程时,我发现常规的sort慢得多。 stable_sort解决了速度问题。