Search code examples
c++mfcqsort

Is qsort thread safe?


I have some old code that uses qsort to sort an MFC CArray of structures but am seeing the occasional crash that may be down to multiple threads calling qsort at the same time. The code I am using looks something like this:

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();

I am about to refactor this horrible code to use std::sort instead but wondered if the above is actually unsafe?

EDIT: Sorter::DoSort is actually a static function but uses no static variables itself.

EDIT2: The SortProc function has been changed to match the real code.


Solution

  • Your problem doesn't necessarily have anything to do with thread saftey.

    The sort callback function takes in pointers to each item, not the item itself. Since you are sorting Foo* what you actually want to do is access the parameters as Foo**, like this:

    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;
    }