我有一些旧的代码使用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功能已更改为与实际代码匹配。
答案 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
解决了速度问题。