2 wulianxuyang wulianxuyang 于 2015.06.30 08:33 提问

C++多线程WaitForMultipleObject 返回值为87 怎么回事

我贴一下我的代码,为什么会出现返回87的问题

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <windows.h>
#include <map>
using namespace std;

#define random   (rand()*1000)/RAND_MAX // random audience
int movieNumber;
int Count[1000];
HANDLE Mutex[1000];
HANDLE HallMutex[3];
map<int ,DWORD >MAP;

DWORD WINAPI VideoShow(LPVOID vid) {
    int i = (int)vid;
    printf("来个一个观众,想看%d影片\n",i);
    WaitForSingleObject(Mutex[i],-1);
        Count[i]++;
        if (Count[i] == 1) {
            DWORD index = WaitForMultipleObjects(3,HallMutex,FALSE,-1);
            if (index == WAIT_OBJECT_0 || index == WAIT_OBJECT_0 + 1 || index == WAIT_OBJECT_0 + 2) {
                MAP[i] = index - WAIT_OBJECT_0;
                printf("观众进入录像厅\n");
                printf("录像厅%d正在放映影片%d,有%d个观众\n",index,i,1);
            }
            else {
                ExitProcess(GetLastError());
            }
        }
        else {
            printf("观众进入录像厅\n");
            printf("录像厅%d正在放映影片%d,有%d个观众\n",MAP[i],i,Count[i]);
        }
    ReleaseMutex(Mutex[i]);
    Sleep(2000);
    WaitForSingleObject(Mutex[i],-1);
        Count[i]--;
        printf("有一个观众从正在播放影片%d的录像厅%d离开,还有%d个人\n",i,MAP[i],Count[i]);
        if (Count[i] == 0) {
            printf("录像厅%d放映结束\n",MAP[i]);
            ReleaseMutex(HallMutex[MAP[i]]);
        }
    ReleaseMutex(Mutex[i]);
}

int main () {
    printf("请输入电影院里电影的数目\n");
    cin >> movieNumber;
    for (int i = 0;i < 3;i++) {
        HallMutex[i] = CreateMutex(NULL,0,NULL);
    }
    for (int i = 0;i < movieNumber;i++) {
        Mutex[i] = CreateMutex(NULL,0,NULL);
    }
    HANDLE hThread;
    while (1) {
        Sleep(random);
        DWORD a = rand() % movieNumber;
        hThread = CreateThread(NULL,0,VideoShow,LPVOID(a),0,NULL);
    }
}

6个回答

gamefinity
gamefinity   Rxr 2015.06.30 20:08
已采纳

如oyljerry所说,你的129是WAIT_ABANDONED_0+1
这个是指:有一个Mutex,它的拥有者线程已经结束,但是那个线程没有释放Mutex。
为此,我以5执行了你的代码,结果如下

请输入电影院里电影的数目
5
来个一个观众,想看2影片
观众进入录像厅
录像厅0正在放映影片2,有1个观众
来个一个观众,想看0影片
观众进入录像厅
录像厅1正在放映影片0,有1个观众
来个一个观众,想看4影片
观众进入录像厅
录像厅2正在放映影片4,有1个观众
来个一个观众,想看3影片
来个一个观众,想看4影片
观众进入录像厅
录像厅2正在放映影片4,有2个观众
有一个观众从正在播放影片2的录像厅0离开,还有0个人
录像厅0放映结束
观众进入录像厅
录像厅0正在放映影片3,有1个观众
来个一个观众,想看0影片
观众进入录像厅
录像厅1正在放映影片0,有2个观众
有一个观众从正在播放影片0的录像厅1离开,还有1个人
有一个观众从正在播放影片4的录像厅2离开,还有1个人
来个一个观众,想看2影片
LastError = 87

打印LastError的位置就是出现129的时候,经分析,执行的线程情况如下,其中A.B.C...代表来的人(在本例中相当于线程),1,2,3代表影片编号

+-等--+-1厅-+-2厅-+-3厅-+
| A2--|->A2 |     |     |
| B0--|-----|->B0 |     |
| C4--|-----|-----|->C4 |
| D3  |     |     |     |
| E4--|-----|-----|->E4 |
| A2<-|--A2 |     |     |
| D3--|->D3 |     |     |
| F0--|-----|->F0 |     |
| B0<-|-----|--B0 |     |
| C4<-|-----|-----|--C4 |
| G2  |     |     |     |ERROR

由此可见在F0来看电影之后,B0离开了电影院.而2厅的Mutex是B0线程创建的.因此它退出但是没有ReleaseMutex(当然是因为业务如此)
然后到G2的时候,需要找一个厅时,就会报129(WAIT_ABANDONED_0+1)
解决方法,对如题的简单应用来说,可以直接忽略WAIT_ABANDONED_0这组数据重新等待,因此把代码略改一下,如下所示

#include <iostream>
#include <cstdio>
#include <cstring>
#include <windows.h>
#include <map>
using namespace std;

#define random   (rand()*1000)/RAND_MAX // random audience
int movieNumber;
int Count[1000];
HANDLE Mutex[1000];
HANDLE HallMutex[3];
map<int, DWORD >MAP;

DWORD WINAPI VideoShow(LPVOID vid) {
    int i = (int)vid;
    printf("来个一个观众,想看%d影片\n", i);
    WaitForSingleObject(Mutex[i], -1);
    Count[i]++;
    if (Count[i] == 1) {
        DWORD index = 0;
        bool done = false;
        do
        {
            index = WaitForMultipleObjects(3, HallMutex, FALSE, -1);
            if (index == WAIT_OBJECT_0 || index == WAIT_OBJECT_0 + 1 || index == WAIT_OBJECT_0 + 2) {
                MAP[i] = index - WAIT_OBJECT_0;
                printf("观众进入录像厅\n");
                printf("录像厅%d正在放映影片%d,有%d个观众\n", index, i, 1);
                done = true;
            }
            else if (index == 0xFFFFFFFF)
            {
                int e = GetLastError();
                printf("LastError = %d\n", e);
                ExitProcess(e);
            }
            else
            {
                Sleep(0);
            }
        } while (!done);
    }
    else {
        printf("观众进入录像厅\n");
        printf("录像厅%d正在放映影片%d,有%d个观众\n", MAP[i], i, Count[i]);
    }
    ReleaseMutex(Mutex[i]);
    Sleep(2000);
    WaitForSingleObject(Mutex[i], -1);
    Count[i]--;
    printf("有一个观众从正在播放影片%d的录像厅%d离开,还有%d个人\n", i, MAP[i], Count[i]);
    if (Count[i] == 0) {
        printf("录像厅%d放映结束\n", MAP[i]);
        ReleaseMutex(HallMutex[MAP[i]]);
    }
    ReleaseMutex(Mutex[i]);
}

int main() {
    printf("请输入电影院里电影的数目\n");
    cin >> movieNumber;
    for (int i = 0; i < 3; i++) {
        HallMutex[i] = CreateMutex(NULL, 0, NULL);
    }
    for (int i = 0; i < movieNumber; i++) {
        Mutex[i] = CreateMutex(NULL, 0, NULL);
    }
    HANDLE hThread;
    while (1) {
        Sleep(random);
        DWORD a = rand() % movieNumber;
        hThread = CreateThread(NULL, 0, VideoShow, LPVOID(a), 0, NULL);
    }
}

对于较复杂的情况,这样使用可能引起其他的同步问题。在这样的情况下,建议对每个放映厅创建线程,单独管理。

gamefinity
gamefinity 至于说WAIT_ABANDONED_0加0,1,2,是直接指示出了被释放线程的Mutex号
2 年多之前 回复
gamefinity
gamefinity   Rxr 2015.06.30 09:05

是GetLastError返回87还是WaitForMultipleObjects返回87?
WaitForMultipleObjects应该不会返回87的。
GetLastError返回87是参数错误。
看程序应该是第二种情况。

wulianxuyang
wulianxuyang   2015.06.30 09:12

对,WatiForMultipleObjects返回129,但是我传的参数的个数是3,怎么可能返回129呢,不知道哪里错了 知常曰明

bdmh
bdmh   Ds   Rxr 2015.06.30 09:13

你可能是这个问题
http://blog.csdn.net/guanzhongs/article/details/1544464
返回值Index和WAIT_OBJECT_0关系

最小的是WAIT_OBJECT_0
后面用WAIT_ABANDONED_0 + nCount – 1

oyljerry
oyljerry   Ds   Rxr 2015.06.30 09:48

WAIT_ABANDONED_0 is defined as 0x00000080L.)

WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount– 1)
If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled and at least one of the objects is an abandoned mutex object.
If bWaitAll is FALSE, the return value minus WAIT_ABANDONED_0 indicates the lpHandles array index of an abandoned mutex object that satisfied the wait. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
If a mutex was protecting persistent state information, you should check it for consistency.

129是WAIT_ABANDONED_0+1

wulianxuyang
wulianxuyang   2015.06.30 09:51

回复 oyljerry 为什么返回值还有0 1 2

Csdn user default icon
上传中...
上传图片
插入图片