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
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à.