Question

J'ai un vieux code qui utilise qsort pour trier un MFC CArray des structures, mais je vois le plantage occasionnel que peut être réduit à plusieurs threads appelant qsort en même temps. Le code que je utilise ressemble à quelque chose comme ceci:

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

Je suis sur le point de factoriser ce code horrible à utiliser au lieu std::sort mais me demandais si ce qui précède est en fait dangereux?

EDIT: Sorter::DoSort est en fait une fonction statique, mais utilise pas de variables statiques lui-même

.

EDIT2. La fonction SortProc a été modifiée pour correspondre au code réel

Était-ce utile?

La solution

Votre problème ne doit pas nécessairement quelque chose à voir avec le fil saftey.

La fonction de rappel de tri prend en pointeurs pour chaque élément, et non l'élément lui-même. Puisque vous triez Foo* ce que vous voulez vraiment faire est d'accéder aux paramètres comme Foo**, comme ceci:

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

Autres conseils

Votre SortProc ne retourne pas des résultats corrects, et cela conduit probablement à la corruption de la mémoire par quelque chose en supposant que les données sont, bien, triée après que vous obtenez fait les trier. Vous pourriez même dirigerai qsort dans la corruption comme il essaie de trier, mais bien sûr par la mise en œuvre varie.

La fonction de comparaison pour qsort doit retourner négatif si le premier objet est inférieure à la seconde, de zéro si elles sont égales et positives autrement. Votre code actuel ne retourne jamais 0 ou 1, et retourne 1 lorsque vous devez retournerez négatif.

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 ++ ne fait pas vraiment de garanties sur la sécurité de fil. A propos de la plupart, vous pouvez dire est que, soit plusieurs lecteurs ou un seul auteur à une structure de données seront OK. Toute combinaison de lecteurs et écrivains, et vous devez serialise l'accès en quelque sorte.

Depuis que vous avez taguée votre question avec tag MFC Je suppose que vous devez sélectionner la bibliothèque d'exécution multi-thread dans les paramètres du projet.

En ce moment, votre code est thread-safe, mais inutile, comme la méthode DoSort-utilise uniquement des variables locales, et ne retourne même pas quoi que ce soit. Si les données que vous triez est membre de trieuse, il n'est pas sûr d'appeler la fonction de plusieurs threads. En Gerenal, lire sur réentrée , cela peut vous donner une idée de ce que vous devez rechercher.

ce qui le rend thread-safe, à savoir si votre objet sont thread-safe, par exemple pour faire qsort thread-safe, vous devez vous assurer que tout ce qui écrire ou lire ou à partir et à l'objet sont thread-safe.

La page de manuel pthreads énumère les fonctions standard qui ne sont pas nécessaires pour être thread-safe. qsort ne figure pas parmi eux, il est donc nécessaire d'être thread-safe dans Posix .

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

Je ne peux pas trouver la liste équivalente pour Windows, cependant, c'est donc pas vraiment une réponse à votre question. Je serais un peu surpris si c'était différent.

Sachez ce que « thread-safe » dans ce contexte, bien que. Cela signifie que vous pouvez appeler la même fonction simultanément sur différents tableaux - cela ne signifie pas que l'accès simultané aux mêmes données via qsort est sûr (il est)

.

En un mot d'avertissement, vous trouverez peut-être std::sort est pas aussi rapide que qsort. Si vous trouvez que std::stable_sort try.

J'ai écrit un compresseur BWT basé sur le code présenté mon Mark Nelson Dr Dobbs et quand je me suis retourné dans les classes, je trouve que sort régulière était beaucoup plus lent. stable_sort fixe les problèmes de vitesse.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top