Domanda

ho qualche vecchio codice che utilizza qsort per ordinare un CArray MFC delle strutture, ma sto vedendo l'incidente occasionale che possono essere giù a più thread di chiamata qsort allo stesso tempo. Il codice che sto usando simile a questa:

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

che sto per refactoring questo codice orribile da usare std::sort posto ma chiedevo se quanto sopra è in realtà pericoloso?

EDIT: Sorter::DoSort è in realtà una funzione statica, ma non usa le variabili statiche si

.

EDIT2:. La funzione SortProc è stata modificata in modo che corrisponda il codice vero e proprio

È stato utile?

Soluzione

Il tuo problema non deve necessariamente a che fare con filo saftey.

La funzione di ordinamento di callback prende in puntatori a ciascun elemento, non l'oggetto in sé. Dal momento che si sta ordinando Foo* quello che realmente vuole fare è accedere ai parametri come Foo**, in questo modo:

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

Altri suggerimenti

Il tuo SortProc non restituisce risultati corretti, e questo probabilmente porta alla corruzione della memoria da qualcosa assumendo che i dati sono, beh, allineati dopo si ottiene fatto smistamento. Si potrebbe anche essere conducendo qsort nella corruzione in quanto cerca di ordinare, ma che ovviamente varia a seconda implementazione.

La funzione di comparazione per qsort deve restituire negativo se il primo oggetto è minore del secondo, zero se sono uguali, e positivo altrimenti. Il codice corrente sempre e solo restituisce 0 o 1, e restituisce 1 quando si dovrebbe essere tornando negativo.

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 ++ non ha realmente alcuna garanzia circa la sicurezza thread. Circa la maggior parte si può dire è che o più lettori o un singolo scrittore di una struttura dati saranno OK. Qualsiasi combinazione di lettori e scrittori, ed è necessario puntate l'accesso in qualche modo.

Dal momento che hai contrassegnato tua domanda con tag MFC Suppongo che si dovrebbe selezionare Multi-threaded della libreria di runtime in Impostazioni progetto.

In questo momento, il codice è thread-safe, ma inutile, come il doSort-metodo utilizza solo variabili locali, e non ha nemmeno restituisce nulla. Se i dati si esegue l'ordinamento è un membro del Sorter, allora non è sicuro di chiamare la funzione da più thread. In gerenal, leggere su reentrancy , questo può dare un'idea di ciò che avete bisogno di guardare fuori per.

ciò che rendono thread-safe a dire, se l'oggetto è thread-safe, ad esempio per fare qsort thread-safe è necessario assicurarsi che tutto ciò che scrivere o leggere o da e per l'oggetto è thread-safe.

La pagina pthreads man elenca le funzioni standard che non sono tenuti ad essere thread-safe. qsort non è fra loro, per cui è richiesto di essere thread-safe in POSIX .

http: //www.kernel .org / doc / man-pagine / in linea / pagine / man7 / pthreads.7.html

Non riesco a trovare l'elenco equivalente per Windows, però, quindi questo non è davvero una risposta alla tua domanda. Sarei un po 'sorpreso se era diverso.

Essere consapevoli che cosa significa "thread-safe" in questo contesto, però. Significa che è possibile chiamare la stessa funzione contemporaneamente su diverse matrici - non significa che l'accesso simultaneo agli stessi dati tramite qsort è sicuro (non lo è)

.

Come una parola di avvertimento, si possono trovare std::sort non è veloce come qsort. Se trovate che std::stable_sort tentativo.

Una volta ho scritto un compressore BWT basato sul codice presentato il mio Mark Nelson in Dr Dobbs e quando ho girato in classi ho trovato che sort regolare era molto più lento. stable_sort fissato i problemi di velocità.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top