Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ qsort线程安全吗?_C++_Mfc_Qsort - Fatal编程技术网

C++ qsort线程安全吗?

C++ qsort线程安全吗?,c++,mfc,qsort,C++,Mfc,Qsort,我有一些使用qsort对MFC结构进行排序的旧代码,但我发现偶尔会出现崩溃,这可能是由于多个线程同时调用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

我有一些使用qsort对MFC结构进行排序的旧代码,但我发现偶尔会出现崩溃,这可能是由于多个线程同时调用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();
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;
}
我即将重构这段可怕的代码,改用std::sort,但我想知道上面的代码是否真的不安全

编辑:Sorter::DoSort实际上是一个静态函数,但它本身不使用静态变量


EDIT2:SortProc函数已更改为与实际代码匹配。

C++并不能真正保证线程安全。您最多可以说,对于一个数据结构,多个读卡器或单个写入器都可以。任何读写器的组合,您都需要以某种方式序列化访问。

C++并不能真正保证线程安全。您最多可以说,对于一个数据结构,多个读卡器或单个写入器都可以。读写器的任意组合,您需要以某种方式序列化访问。

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

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

既然您用MFC标记了问题,我想您应该在项目设置中选择多线程运行时库。

既然您用MFC标记了问题,我想您应该在项目设置中选择多线程运行时库。

是什么使它成为线程安全是,无论您的对象是否是线程安全的,例如,要使qsort线程安全,您必须确保向对象写入或从对象读取的任何内容都是线程安全的。

使其线程安全的是,您的对象是否是线程安全的,例如,要使qsort线程安全,您必须确保向对象写入或从对象读取的任何内容都是线程安全的。

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

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

作为警告,您可能会发现std::sort不如qsort快。如果您确实发现了这个问题,请尝试std::stable\u sort


我曾经根据Dobbs博士中Mark Nelson的代码编写了一个BWT压缩器,当我把它转换成类时,我发现常规排序要慢得多。稳定排序解决了速度问题。

作为警告,您可能会发现std::sort不如qsort快。如果您确实发现了这个问题,请尝试std::stable\u sort


我曾经根据Dobbs博士中Mark Nelson的代码编写了一个BWT压缩器,当我把它转换成类时,我发现常规排序要慢得多。稳定排序修复了速度问题。

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

不过,我找不到Windows的等效列表,因此这并不是对您问题的回答。如果是不同的,我会有点惊讶


不过,请注意线程安全在本文中的含义。这意味着您可以在不同的阵列上并发调用相同的函数-这并不意味着通过qsort并发访问相同的数据是安全的,而不是安全的。

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

不过,我找不到Windows的等效列表,因此这并不是对您问题的回答。我会的 有点惊讶,如果它是不同的


不过,请注意线程安全在本文中的含义。这意味着您可以在不同的阵列上并发调用相同的函数-这并不意味着通过qsort并发访问相同的数据是安全的,而不是安全的。

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

sort回调函数接受指向每个项的指针,而不是项本身。因为您正在对Foo*进行排序,所以您实际上要做的是以Foo**的形式访问参数,如下所示:

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

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

sort回调函数接受指向每个项的指针,而不是项本身。因为您正在对Foo*进行排序,所以您实际上要做的是以Foo**的形式访问参数,如下所示:

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


你说的线程安全是什么意思?多个线程同时对多个数组进行排序?多个线程同时对同一数组进行排序?多个线程同时对多个数组进行排序。崩溃也可能是内存损坏,但这段代码似乎是随机崩溃的唯一常见因素。你能发布CArray类吗?我现在很困惑。你能发一下电话号码吗?从多个线程中得到什么参数?为什么在C++中使用Q排序?线程安全是什么意思?多个线程同时对多个数组进行排序?多个线程同时对同一数组进行排序?多个线程同时对多个数组进行排序。崩溃也可能是内存损坏,但这段代码似乎是随机崩溃的唯一常见因素。你能发布CArray类吗?我现在很困惑。你能发一下电话号码吗?什么是从多个线程得到的参数?为什么在C++中使用Q排序?在调用Q排序之后还有更多的代码,但是崩溃总是在SoToPROC本身。在调用Q排序之后还有更多的代码,但是崩溃总是在SORTTROC本身。这是向后的,或者你只是被一个糟糕的实现所困扰。稳定排序有一个非稳定排序没有的额外要求,如果std::Stable_sort真的更快,那么可以重新实现std::sort来调用它。通常,std::sort在速度上优于qsort,因为它可以积极地内联,并且出于同样的原因,可以产生更大的生成代码大小。统计数据并不存在。这是用VC6编写的:为什么要使用VC6?它附带了一个来自Dinkumware的STL实现,实际上有人起诉MSFT或Dinkumware存在法律问题;我不记得是什么阻止了MSFT更新它,甚至每个用户都必须在标题中手动修复bug。当你尝试了一个编译器,它有了过去十几年C++优化经验的好处吗?VC6在1998之前发布在C++标准之前。我同意C++优化是困难的,但是你可以偏向任何基准。即使是这样,你也可能碰到一个与一般行为相反的特定用例,你只会被一个比你的其他情况调整的糟糕的实现所困扰。访问模式、预期/最佳/最坏情况、分支预测以及如何运行测试都很重要。你甚至把自己的基准测试称为非正式的。我使用VC6,因为那是公司当时使用的。奇怪的是,今天我仍在使用VC6,这是另一家公司的产品,尽管它用于维护仍然需要运行但仍然没有多少bug的遗留应用程序。至于尝试一个不同的编译器,我没有得到机会,因为删除关于CString的每一个错误将花费数周的时间。BWT是一个非常大、非常旧的系统的一部分。这是向后的,或者你只是被一个糟糕的实现卡住了。稳定排序有一个非稳定排序没有的额外要求,如果std::Stable_sort真的更快,那么可以重新实现std::sort来调用它。通常,std::sort在速度上优于qsort,因为它可以积极地内联,并且出于同样的原因,可以产生更大的生成代码大小。统计数据并不存在。这是用VC6编写的:为什么要使用VC6?它附带了一个来自Dinkumware的STL实现,实际上有人起诉MSFT或Dinkumware存在法律问题;我不记得是什么阻止了MSFT更新它,甚至每个用户都必须在标题中手动修复bug。当你尝试了一个编译器,它有了过去十几年C++优化经验的好处吗?VC6在1998之前发布在C++标准之前。我同意C++优化是困难的,但是你可以偏向任何基准。即使是这样,你也可能碰到一个与一般行为相反的特定用例,你只会被一个比你的其他情况调整的糟糕的实现所困扰。访问模式,预期/最佳/最坏情况,
分支预测以及如何运行测试都很重要。你甚至把自己的基准测试称为非正式的。我使用VC6,因为那是公司当时使用的。奇怪的是,今天我仍在使用VC6,这是另一家公司的产品,尽管它用于维护仍然需要运行但仍然没有多少bug的遗留应用程序。至于尝试一个不同的编译器,我没有得到机会,因为删除关于CString的每一个错误将花费数周的时间。BWT是一个非常大、非常旧的系统的一部分。但是大多数时候,发布的代码都能正常工作——如果这是正确的话,每次都会崩溃吗?@Rob:不,只有当内存访问导致访问冲突时,正如你发现的那样。即使它看起来有效,您也无法真正访问您认为正在访问的内容,您将得到不可预测的结果。您不正确的强制转换意味着您的代码具有未定义的行为,这不一定会崩溃。是的,我认为这就是问题的原因。棒 极 了但是大多数时候,代码都是有效的——如果这是正确的,那么每次都会崩溃吗?@Rob:不,只有当内存访问导致访问冲突时,正如您所发现的那样。即使它看起来有效,您也无法真正访问您认为正在访问的内容,您将得到不可预测的结果。您不正确的强制转换意味着您的代码具有未定义的行为,这不一定会崩溃。是的,我认为这就是问题的原因。棒 极 了