문제
사용하는 오래된 코드가 있습니다 qsort
MFC를 정렬합니다 CArray
구조물이지만 가끔 충돌이 발생하고 있습니다 5월 여러 스레드가 호출됩니다 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
대신 위의 것이 실제로 안전하지 않은지 궁금하십니까?
편집하다: Sorter::DoSort
실제로 정적 함수이지만 정적 변수 자체를 사용하지 않습니다.
edit2 : SortProc 함수는 실제 코드와 일치하도록 변경되었습니다.
해결책
당신의 문제가 반드시 Thread Saftey와 관련이있는 것은 아닙니다.
정렬 콜백 함수는 항목 자체가 아닌 각 항목에 대한 포인터를 사용합니다. 정렬하기 때문에 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;
}
다른 팁
SortProc은 올바른 결과를 반환하지 않으므로 데이터가 정렬 된 후에 데이터가 정렬되었다고 가정하여 메모리 손상으로 이어질 수 있습니다. QSORT가 분류하려고 할 때 QSORT를 부패로 이끌 수도 있지만 물론 구현에 따라 다릅니다.
QSORT의 비교 함수는 첫 번째 객체가 두 번째 객체보다 작고, 그렇지 않으면 긍정적 인 경우 ZERO보다 음수를 반환해야합니다. 현재 코드는 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;
}
C ++는 실제로 스레드 안전에 대한 보장을하지 않습니다. 당신이 말할 수있는 가장 많은 것은 여러 독자 나 데이터 구조에 대한 단일 작가가 괜찮다는 것입니다. 독자와 작가의 모든 조합이 있으므로 어떻게 든 액세스 할 수 있습니다.
질문을 태그로 지정했기 때문에 MFC
태그 프로젝트 설정에서 멀티 스레드 런타임 라이브러리를 선택해야한다고 가정합니다.
DoSort-Method는 로컬 변수 만 사용하고 아무것도 반환하지 않기 때문에 현재 코드는 스레드 안전하지만 쓸모가 없습니다. 정렬중인 데이터가 분류기의 구성원 인 경우 여러 스레드에서 기능을 호출하는 것이 안전하지 않습니다. 게레날에서는 읽으십시오 재창조, 이것은 당신이 무엇을 찾아야하는지에 대한 아이디어를 줄 수 있습니다.
스레드를 안전하게 만드는 것은 객체가 스레드 안전한지 여부, 예를 들어 QSORT 스레드-안전을 만들려면 쓰기 또는 읽기 또는 객체에 대한 객체에 안전한 스레드를 안전하게 보장해야합니다.
PTHREADS MAN 페이지에는 스레드 안전이 필요하지 않은 표준 기능이 나와 있습니다. QSORT는 그들 중 하나가 아니므로 스레드-안전해야합니다. POSIX에서.
http://www.kernel.org/doc/man-pages/online/pages/man7/pthreads.7.html
그러나 Windows의 동등한 목록을 찾을 수는 없으므로 실제로 귀하의 질문에 대한 답이 아닙니다. 그것이 다르면 약간 놀랐습니다.
그러나이 맥락에서 "스레드-안전"이 무엇을 의미하는지 알아야합니다. 즉, 다른 배열에서 동시에 동일한 기능을 동시에 호출 할 수 있음을 의미합니다. QSORT를 통해 동일한 데이터에 대한 동시 액세스가 안전하다는 의미는 아닙니다 (그렇지 않음).
경고의 한마디로, 당신은 찾을 수 있습니다 std::sort
빠르지 않습니다 qsort
. 당신이 그것을 찾으면 시도하십시오 std::stable_sort
.
한 번은 Dobbs 박사에 Mark Nelson을 제시 한 코드를 기반으로 BWT 압축기를 썼고 수업으로 전환했을 때 그 규칙을 찾았습니다. sort
훨씬 느 렸습니다. stable_sort
속도 문제를 수정했습니다.