【问题标题】:Recursive synchronization递归同步
【发布时间】:2012-10-19 08:33:01
【问题描述】:

在我的应用程序中,两个线程调用相同的递归函数,应该将数据输出到某个文件。我不知道如何同步这些线程以输出正确的数据。我尝试了一些带有互斥锁的变体(在代码中使用 /** n **/ 注释),但它不起作用(输出数据来自不同的线程)。如何组织同步(我应该只使用 WinAPI 和 std)。伪代码如下:

HANDLE hMutex = CreateMutex(NULL,FALSE, 0);
wchar_t** HelpFunction(wchar_t const* p, int *t)
{
    do
    {
        /**** 1 ****/ //WaitForSingleObject(hMutex, INFINITE);
        wchar_t* otherP= someFunction();
        if(...)
        {
            /**** 2 ****/ //WaitForSingleObject(hMutex, INFINITE);
            //File's output should be here
            //Outputing p
            /**** 2 ****/ //ReleaseMutex(hMutex);
        }
        if(...)
        {
            HelpFunction(otherP, t);
        }
        /**** 1 ****/ //ReleaseMutex(hMutex);
    }while(...);
}
unsigned int WINAPI ThreadFunction( void* p)
{
    int t = 0;
    /**** 3 ****/ //WaitForSingleObject(hMutex, INFINITE);
    wchar_t** res = HelpFunction((wchar_t *)p, &t);
    /**** 3 ****/ //ReleaseMutex(hMutex);
    return 0;
}
void _tmain()
{
    HANDLE hThreads[2];
    hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, ThreadFunction, L"param1", 0, NULL);
    hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, ThreadFunction, L"param2", 0, NULL);
    WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
}

【问题讨论】:

    标签: c++ c multithreading winapi


    【解决方案1】:

    对于 Windows API,如果它是单个进程,则最好使用关键部分。

    临界区不需要 WaitForSingleObject,只有在等待某些数据写入时才使用它。

    我猜你正在同步的是文件写入,所以每个线程一次写入一条完整的记录。 (确保刷新所有缓冲区)。

    你会打电话的

    EnterCriticalSection

    当你到达敏感部分时

    LeaveCriticalSection

    在敏感部分的末尾。

    并查看here 以获取更多详细信息 API。

    这里的递归无关紧要,只要您在递归时没有持有“锁”,即您不在关键部分代码中进行递归。当您使用所示代码进行递归时,它不会产生新线程。我不知道你是否期待它。

    我实际上在您的 HelpFunction 中看不到任何文件 I/O。但是,我确实看到了您刚刚称为 t 的指针。它是两个线程的相同指针,并且它是非常量的。因此,如果两个线程都将写入该 int,您可能也需要同步它。再一次,您的代码实际上并未显示该指针的使用方式。

    【讨论】:

    • 是的,这是一个单一的过程,但我担心我会得到相同的结果。输出数据将来自不同线程的混合
    • 我对 CRITICAL_SECTION 有所了解,Mutex 也应该可以工作。但在我的情况下存在递归。输出是混合的?我不知道我能做什么?
    • 是的,如果两个线程写入同一个输出文件,你会得到不同线程的输出。重要的是要确保单个“记录”看起来不间断。因此,您在记录写入期间“锁定”。
    • 是的,但我得到 在在某些情况下,但预期 我已经尝试了 CRITICAL_SECTION 和 Mutex,但结果相同
    • @Vsevywniy 在离开临界区之前刷新输出。对于 FILE*,我似乎记得该函数称为 fflush。顺便说一句,您将其标记为 C++,但代码看起来像 C。例如,使用范围锁。谷歌 RAII。