关于多线程等待的一个小问题

eof_xien 2014-07-03 11:23:26
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <process.h>
#include <time.h>
#define MIN(_x,_y) ((_x) < (_y)) ? (_x) : (_y)
//设置控制台输出颜色
BOOL SetConsoleColor(WORD wAttributes)
{
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE)
return FALSE;

return SetConsoleTextAttribute(hConsole, wAttributes);
}
volatile int count;
volatile int molecules_left;
int NUM;
CRITICAL_SECTION g_cs;
//HANDLE g_hEventHatomEmpty, g_hEventHatomFull;
HANDLE g_hEventOatomFull,g_hEventOatomEmpty;
HANDLE g_hSemaphoreHEmpty, g_hSemaphoreHFull;



unsigned int __stdcall H_atomThread(PVOID pM)
{
int Hcount = 0;
WaitForSingleObject(g_hSemaphoreHEmpty, INFINITE);
EnterCriticalSection(&g_cs);
printf("线程编号%d的H原子已经从缓冲池中被取出来!\n",GetCurrentThreadId());
Hcount++;
LeaveCriticalSection(&g_cs);
//告诉water线程H原子已到位
ReleaseSemaphore(g_hSemaphoreHFull, 1, NULL);

return 0;

}

unsigned int __stdcall O_atomThreadFun(PVOID pM)
{

WaitForSingleObject(g_hEventOatomEmpty, INFINITE);
EnterCriticalSection(&g_cs);
printf("线程编号%d的O原子已经从缓冲池中被取出来!\n",GetCurrentThreadId());
LeaveCriticalSection(&g_cs);
//告诉water线程O原子已到位
SetEvent(g_hEventOatomFull);

return 0;

}
unsigned int __stdcall WaterThreadFun(PVOID pM)
{

WaitForSingleObject(g_hSemaphoreHFull, INFINITE);
WaitForSingleObject(g_hSemaphoreHFull, INFINITE);
WaitForSingleObject(g_hEventOatomFull, INFINITE);
EnterCriticalSection(&g_cs);
count++;
SetConsoleColor(FOREGROUND_GREEN);
printf("2个H原子与1个O原子已经结合成1个水分子!共合成%d个水分子\n",count);
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

//告诉生产者 H,O原子已经消耗完毕
if (molecules_left-count>0)
{
printf("1%d\n", molecules_left);
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
SetEvent(g_hEventOatomEmpty);
ReleaseSemaphore(g_hSemaphoreHEmpty, 2, NULL);
}
else
{
printf("水分子已经全部结合完成,没有多余的元素继续合成!!\n");
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
}
LeaveCriticalSection(&g_cs);
return 0;
}

int main()
{

//初始化关键段
int total_atoms = 300;
int H_atoms, O_atoms, expected_molecules;
srand((unsigned)time(0)); //改变随机种子
H_atoms = rand() % 150+80;
O_atoms = total_atoms - H_atoms;
expected_molecules = MIN(H_atoms / 2, O_atoms);
molecules_left = expected_molecules;
printf("共有%d个H元素,%d个O元素,预计能合成%d个水分子!\n", H_atoms, O_atoms, expected_molecules);
InitializeCriticalSection(&g_cs);
//自动置位,初始已触发
g_hEventHatomEmpty = CreateEvent(NULL, TRUE, TRUE, NULL);
g_hEventHatomFull = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hEventOatomEmpty = CreateEvent(NULL, FALSE, TRUE, NULL);
g_hEventOatomFull = CreateEvent(NULL, FALSE, FALSE, NULL);
g_hSemaphoreHEmpty = CreateSemaphore(NULL, 2, 2, NULL);
g_hSemaphoreHFull = CreateSemaphore(NULL, 0, 2, NULL);
NUM = O_atoms + H_atoms;
HANDLE hThread[350];



for (int i = 0; i < H_atoms; i++)
{
hThread[i] = (HANDLE)_beginthreadex(NULL, 0, H_atomThread, NULL, 0, NULL);
}

for (int j = H_atoms; j < NUM; j++)
{
hThread[j] = (HANDLE)_beginthreadex(NULL, 0, O_atomThreadFun, NULL, 0, NULL);
}

hThread[NUM] = (HANDLE)_beginthreadex(NULL, 0, WaterThreadFun, NULL, 0, NULL);
WaitForMultipleObjects(NUM+1, hThread, TRUE, INFINITE);


for (int i = 0; i < NUM+1; i++)
CloseHandle(hThread[i]);

//摧毁事件与关键段
//CloseHandle(g_hEventHatomEmpty);
//CloseHandle(g_hEventHatomFull);
CloseHandle(g_hEventOatomEmpty);
CloseHandle(g_hEventOatomFull);
CloseHandle(g_hSemaphoreHEmpty);
CloseHandle(g_hSemaphoreHFull);
DeleteCriticalSection(&g_cs);
return 0;
}

代码如上,思路是创建了N个H元素的线程与M个O元素的线程,还有一个生成水的WATER线程,water线程必须等待两个H原子,一个O原子才能生产一个水,我用了一个Event控制O元素的投放,用Semaphore控制H元素的投放,信号量最大资源数目是2,当H原子没投放一次,则g_hSemaphoreHFull加1,water线程的用两个waitfor控制水的生成,现在的问题是程序只运行一遍,没找到在那里死锁了……大神们帮看看
...全文
168 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
eof_xien 2014-07-03
  • 打赏
  • 举报
回复
谢谢楼上!吃饭回来研究一下
赵4老师 2014-07-03
  • 打赏
  • 举报
回复
仅供参考
//循环向a函数每次发送200个字节长度(这个是固定的)的buffer,
//a函数中需要将循环传进来的buffer,组成240字节(也是固定的)的新buffer进行处理,
//在处理的时候每次从新buffer中取两个字节打印
#ifdef WIN32
    #pragma warning(disable:4996)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
    #include <windows.h>
    #include <process.h>
    #include <io.h>
    #define  MYVOID             void
    #define  vsnprintf          _vsnprintf
#else
    #include <unistd.h>
    #include <sys/time.h>
    #include <pthread.h>
    #define  CRITICAL_SECTION   pthread_mutex_t
    #define  MYVOID             void *
#endif
//Log{
#define MAXLOGSIZE 20000000
#define MAXLINSIZE 16000
#include <time.h>
#include <sys/timeb.h>
#include <stdarg.h>
char logfilename1[]="MyLog1.log";
char logfilename2[]="MyLog2.log";
static char logstr[MAXLINSIZE+1];
char datestr[16];
char timestr[16];
char mss[4];
CRITICAL_SECTION cs_log;
FILE *flog;
#ifdef WIN32
void Lock(CRITICAL_SECTION *l) {
    EnterCriticalSection(l);
}
void Unlock(CRITICAL_SECTION *l) {
    LeaveCriticalSection(l);
}
void sleep_ms(int ms) {
    Sleep(ms);
}
#else
void Lock(CRITICAL_SECTION *l) {
    pthread_mutex_lock(l);
}
void Unlock(CRITICAL_SECTION *l) {
    pthread_mutex_unlock(l);
}
void sleep_ms(int ms) {
    usleep(ms*1000);
}
#endif
void LogV(const char *pszFmt,va_list argp) {
    struct tm *now;
    struct timeb tb;

    if (NULL==pszFmt||0==pszFmt[0]) return;
    vsnprintf(logstr,MAXLINSIZE,pszFmt,argp);
    ftime(&tb);
    now=localtime(&tb.time);
    sprintf(datestr,"%04d-%02d-%02d",now->tm_year+1900,now->tm_mon+1,now->tm_mday);
    sprintf(timestr,"%02d:%02d:%02d",now->tm_hour     ,now->tm_min  ,now->tm_sec );
    sprintf(mss,"%03d",tb.millitm);
    printf("%s %s.%s %s",datestr,timestr,mss,logstr);
    flog=fopen(logfilename1,"a");
    if (NULL!=flog) {
        fprintf(flog,"%s %s.%s %s",datestr,timestr,mss,logstr);
        if (ftell(flog)>MAXLOGSIZE) {
            fclose(flog);
            if (rename(logfilename1,logfilename2)) {
                remove(logfilename2);
                rename(logfilename1,logfilename2);
            }
        } else {
            fclose(flog);
        }
    }
}
void Log(const char *pszFmt,...) {
    va_list argp;

    Lock(&cs_log);
    va_start(argp,pszFmt);
    LogV(pszFmt,argp);
    va_end(argp);
    Unlock(&cs_log);
}
//Log}
#define ASIZE    200
#define BSIZE    240
#define CSIZE      2
char Abuf[ASIZE];
char Cbuf[CSIZE];
CRITICAL_SECTION cs_HEX ;
CRITICAL_SECTION cs_BBB ;
struct FIFO_BUFFER {
    int  head;
    int  tail;
    int  size;
    char data[BSIZE];
} BBB;
int No_Loop=0;
void HexDump(int cn,char *buf,int len) {
    int i,j,k;
    char binstr[80];

    Lock(&cs_HEX);
    for (i=0;i<len;i++) {
        if (0==(i%16)) {
            sprintf(binstr,"%03d %04x -",cn,i);
            sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
        } else if (15==(i%16)) {
            sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
            sprintf(binstr,"%s  ",binstr);
            for (j=i-15;j<=i;j++) {
                sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');
            }
            Log("%s\n",binstr);
        } else {
            sprintf(binstr,"%s %02x",binstr,(unsigned char)buf[i]);
        }
    }
    if (0!=(i%16)) {
        k=16-(i%16);
        for (j=0;j<k;j++) {
            sprintf(binstr,"%s   ",binstr);
        }
        sprintf(binstr,"%s  ",binstr);
        k=16-k;
        for (j=i-k;j<i;j++) {
            sprintf(binstr,"%s%c",binstr,('!'<buf[j]&&buf[j]<='~')?buf[j]:'.');
        }
        Log("%s\n",binstr);
    }
    Unlock(&cs_HEX);
}
int GetFromRBuf(int cn,CRITICAL_SECTION *cs,FIFO_BUFFER *fbuf,char *buf,int len) {
    int lent,len1,len2;

    lent=0;
    Lock(cs);
    if (fbuf->size>=len) {
        lent=len;
        if (fbuf->head+lent>BSIZE) {
            len1=BSIZE-fbuf->head;
            memcpy(buf     ,fbuf->data+fbuf->head,len1);
            len2=lent-len1;
            memcpy(buf+len1,fbuf->data           ,len2);
            fbuf->head=len2;
        } else {
            memcpy(buf     ,fbuf->data+fbuf->head,lent);
            fbuf->head+=lent;
        }
        fbuf->size-=lent;
    }
    Unlock(cs);
    return lent;
}
MYVOID thdB(void *pcn) {
    char        *recv_buf;
    int          recv_nbytes;
    int          cn;
    int          wc;
    int          pb;

    cn=(int)pcn;
    Log("%03d thdB              thread begin...\n",cn);
    while (1) {
        sleep_ms(10);
        recv_buf=(char *)Cbuf;
        recv_nbytes=CSIZE;
        wc=0;
        while (1) {
            pb=GetFromRBuf(cn,&cs_BBB,&BBB,recv_buf,recv_nbytes);
            if (pb) {
                Log("%03d recv %d bytes\n",cn,pb);
                HexDump(cn,recv_buf,pb);
                sleep_ms(1);
            } else {
                sleep_ms(1000);
            }
            if (No_Loop) break;//
            wc++;
            if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);
        }
        if (No_Loop) break;//
    }
#ifndef WIN32
    pthread_exit(NULL);
#endif
}
int PutToRBuf(int cn,CRITICAL_SECTION *cs,FIFO_BUFFER *fbuf,char *buf,int len) {
    int lent,len1,len2;

    Lock(cs);
    lent=len;
    if (fbuf->size+lent>BSIZE) {
        lent=BSIZE-fbuf->size;
    }
    if (fbuf->tail+lent>BSIZE) {
        len1=BSIZE-fbuf->tail;
        memcpy(fbuf->data+fbuf->tail,buf     ,len1);
        len2=lent-len1;
        memcpy(fbuf->data           ,buf+len1,len2);
        fbuf->tail=len2;
    } else {
        memcpy(fbuf->data+fbuf->tail,buf     ,lent);
        fbuf->tail+=lent;
    }
    fbuf->size+=lent;
    Unlock(cs);
    return lent;
}
MYVOID thdA(void *pcn) {
    char        *send_buf;
    int          send_nbytes;
    int          cn;
    int          wc;
    int           a;
    int          pa;

    cn=(int)pcn;
    Log("%03d thdA              thread begin...\n",cn);
    a=0;
    while (1) {
        sleep_ms(100);
        memset(Abuf,a,ASIZE);
        a=(a+1)%256;
        if (16==a) {No_Loop=1;break;}//去掉这句可以让程序一直循环直到按Ctrl+C或Ctrl+Break或当前目录下存在文件No_Loop
        send_buf=(char *)Abuf;
        send_nbytes=ASIZE;
        Log("%03d sending %d bytes\n",cn,send_nbytes);
        HexDump(cn,send_buf,send_nbytes);
        wc=0;
        while (1) {
            pa=PutToRBuf(cn,&cs_BBB,&BBB,send_buf,send_nbytes);
            Log("%03d sent %d bytes\n",cn,pa);
            HexDump(cn,send_buf,pa);
            send_buf+=pa;
            send_nbytes-=pa;
            if (send_nbytes<=0) break;//
            sleep_ms(1000);
            if (No_Loop) break;//
            wc++;
            if (wc>3600) Log("%03d %d==wc>3600!\n",cn,wc);
        }
        if (No_Loop) break;//
    }
#ifndef WIN32
    pthread_exit(NULL);
#endif
}
int main() {
#ifdef WIN32
    InitializeCriticalSection(&cs_log);
    InitializeCriticalSection(&cs_HEX );
    InitializeCriticalSection(&cs_BBB );
#else
    pthread_t threads[2];
    int threadsN;
    int rc;
    pthread_mutex_init(&cs_log,NULL);
    pthread_mutex_init(&cs_HEX,NULL);
    pthread_mutex_init(&cs_BBB,NULL);
#endif
    Log("Start===========================================================\n");

    BBB.head=0;
    BBB.tail=0;
    BBB.size=0;

#ifdef WIN32
    _beginthread((void(__cdecl *)(void *))thdA,0,(void *)1);
    _beginthread((void(__cdecl *)(void *))thdB,0,(void *)2);
#else
    threadsN=0;
    rc=pthread_create(&(threads[threadsN++]),NULL,thdA,(void *)1);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1);
    rc=pthread_create(&(threads[threadsN++]),NULL,thdB,(void *)2);if (rc) Log("%d=pthread_create %d error!\n",rc,threadsN-1);
#endif

    if (!access("No_Loop",0)) {
        remove("No_Loop");
        if (!access("No_Loop",0)) {
            No_Loop=1;
        }
    }
    while (1) {
        sleep_ms(1000);
        if (No_Loop) break;//
        if (!access("No_Loop",0)) {
            No_Loop=1;
        }
    }
    sleep_ms(3000);
    Log("End=============================================================\n");
#ifdef WIN32
    DeleteCriticalSection(&cs_BBB );
    DeleteCriticalSection(&cs_HEX );
    DeleteCriticalSection(&cs_log);
#else
    pthread_mutex_destroy(&cs_BBB);
    pthread_mutex_destroy(&cs_HEX);
    pthread_mutex_destroy(&cs_log);
#endif
    return 0;
}
《Windows核心编程》 Synchronization Functions The following functions are used in synchronization. CancelWaitableTimer CreateEvent CreateMutex CreateSemaphore CreateWaitableTimer DeleteCriticalSection EnterCriticalSection GetOverlappedResult InitializeCriticalSection InitializeCriticalSectionAndSpinCount InterlockedCompareExchange InterlockedDecrement InterlockedExchange InterlockedExchangeAdd InterlockedIncrement LeaveCriticalSection MsgWaitForMultipleObjects MsgWaitForMultipleObjectsEx OpenEvent OpenMutex OpenSemaphore OpenWaitableTimer PulseEvent QueueUserAPC ReleaseMutex ReleaseSemaphore ResetEvent SetCriticalSectionSpinCount SetEvent SetWaitableTimer SignalObjectAndWait TimerAPCProc TryEnterCriticalSection WaitForMultipleObjects WaitForMultipleObjectsEx WaitForSingleObject WaitForSingleObjectEx
layershow 2014-07-03
  • 打赏
  • 举报
回复
引用 11 楼 eof_xien 的回复:
想问一个问题比如 hThread[i] = (HANDLE)_beginthreadex(NULL, 0, H_atomThread, &i, 0, NULL) 这里面的这个传入的参数i能不能标识这个线程? 因为有的时候我在线程里面输出 "i"的值的时候发现会重复出现,我理解为没能实现线程间的同步,不知这种理解是不是正确的? 不过i的值相同输出的两次,getcurrentthreadID()的值又不同,这又是为什么呢?
GetCurrentThreadId 肯定是返回当前线程 ID,这个完全不同是对的,你想用参数标识线程也没问题,但是这里用 i 是错误的 注意这里传入的是指针,你把局部变量 i 的地址传给了每一个线程,他们访问的实际上是同一个东西 如果你有一个 paramters数组像 hThread 一样,分别传进去就没问题,例如 paramters[i] = i; hThread[i] = (HANDLE)_beginthreadex(NULL, 0, H_atomThread, &paramters[i] , 0, NULL)
eof_xien 2014-07-03
  • 打赏
  • 举报
回复
想问一个问题比如 hThread[i] = (HANDLE)_beginthreadex(NULL, 0, H_atomThread, &i, 0, NULL) 这里面的这个传入的参数i能不能标识这个线程? 因为有的时候我在线程里面输出 "i"的值的时候发现会重复出现,我理解为没能实现线程间的同步,不知这种理解是不是正确的? 不过i的值相同输出的两次,getcurrentthreadID()的值又不同,这又是为什么呢?
eof_xien 2014-07-03
  • 打赏
  • 举报
回复
引用 8 楼 layershow 的回复:
[quote=引用 7 楼 eof_xien 的回复:] [quote=引用 5 楼 baichi4141 的回复:] 我在几个线程函数里都没有看到while循环 也就是说,每个线程函数只运行一次就结束 那有啥可等待的?每个线程都是执行一次瞬间完成,等待啥啊?
因为创建了很多线程,有些线程没有得到信号量,不会等待的吗? 另外我在3个线程加上了While函数,情况还是没变。[/quote] 还有 main 函数加 while,进程退了,所有都完蛋了[/quote] 好的,马上就试
eof_xien 2014-07-03
  • 打赏
  • 举报
回复
引用 6 楼 layershow 的回复:
三个线程 和 主程序 都没有循环,都是执行一次就结束了 应该放在一个循环中 ThreadFun { // 线程开始 while (1) { // 没有这个循环,线程很快就结束了 } // 线程结束 }
我在3个子线程中都加了while(1){} 但是没有变化,我再看看
layershow 2014-07-03
  • 打赏
  • 举报
回复
引用 7 楼 eof_xien 的回复:
[quote=引用 5 楼 baichi4141 的回复:] 我在几个线程函数里都没有看到while循环 也就是说,每个线程函数只运行一次就结束 那有啥可等待的?每个线程都是执行一次瞬间完成,等待啥啊?
因为创建了很多线程,有些线程没有得到信号量,不会等待的吗? 另外我在3个线程加上了While函数,情况还是没变。[/quote] 还有 main 函数加 while,进程退了,所有都完蛋了
eof_xien 2014-07-03
  • 打赏
  • 举报
回复
引用 5 楼 baichi4141 的回复:
我在几个线程函数里都没有看到while循环 也就是说,每个线程函数只运行一次就结束 那有啥可等待的?每个线程都是执行一次瞬间完成,等待啥啊?
因为创建了很多线程,有些线程没有得到信号量,不会等待的吗? 另外我在3个线程加上了While函数,情况还是没变。
layershow 2014-07-03
  • 打赏
  • 举报
回复
三个线程 和 主程序 都没有循环,都是执行一次就结束了 应该放在一个循环中 ThreadFun { // 线程开始 while (1) { // 没有这个循环,线程很快就结束了 } // 线程结束 }
baichi4141 2014-07-03
  • 打赏
  • 举报
回复
我在几个线程函数里都没有看到while循环 也就是说,每个线程函数只运行一次就结束 那有啥可等待的?每个线程都是执行一次瞬间完成,等待啥啊?
eof_xien 2014-07-03
  • 打赏
  • 举报
回复
也想过用Event来控制H原子,不过只能设为手动置位,手动置位的过程中,他就并发了很多次,没办法实现
eof_xien 2014-07-03
  • 打赏
  • 举报
回复
只循环了一次,后面的就H,O线程都不继续调用了,头疼啊

64,652

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧