帮忙看下这种结构下,子线程如何和主线程通信

starytx 2017-05-15 04:10:22
CEF3多进程框架,其中的渲染进程以一个win32程序为宿主程序,此程序没有多少代码,就一个入口函数,代码如下:
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
if(!lpCmdLine || *lpCmdLine==0)
return 0;

Cef_ExecuteProcess(hInstance);
return 0;
}

其中Cef_ExecuteProcess(hInstance);可以简单理解为一个会阻塞的函数,直到渲染进程被关闭,在渲染进程中,必须执行这个函数,才会正确显示页面。现在我在后台渲染进程中需要将一些费时的操作,比如压缩或解压操作,放在_beginthreadex库函数开辟的线程中执行,需要知道什么时候处理完毕了以及处理的结果(TRUE/FALSE),如何在处理完毕后通知主线程呢?我可以在开辟线程时传入当前线程的id,在线程函数最后PostThreadMessage,在外部如何接收这个消息并处理呢?因为现在我感觉没有办法接收,因为上边那个cef函数会阻塞,所以不能在那里边搞一个while来GetMessage。或者说哪位有其他可以通知主线程的方式也可以说说。
...全文
190 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2017-05-17
  • 打赏
  • 举报
回复
《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
天际抓根宝 2017-05-17
  • 打赏
  • 举报
回复
引用 12 楼 starytx 的回复:
[quote=引用 10 楼 zhao4zhong1 的回复:] 多进程参考: Microsoft SDK\samples\winbase\SharedMem\Consumer.Cpp Microsoft SDK\samples\winbase\SharedMem\Makefile Microsoft SDK\samples\winbase\SharedMem\Producer.Cpp Microsoft SDK\samples\winbase\SharedMem\Queue.h Microsoft SDK\samples\winbase\SharedMem\ReadMe.Txt Microsoft SDK\samples\winbase\SharedMem\Common.h
我还是详细描述下我的场景吧 比如有个A.cpp,里边有一些函数,比如fun(),这些代码在cef框架中是运行在渲染进程中的。渲染进程将一个无窗口的exe作为宿主程序,这个exe的main里边就执行一个cef的函数(阻塞的),A.cpp是在一个dll中的,但是我经过查看,可以确定在A.cpp的fun()中GetCurrentThreadId和在exe的main中返回的是相同的值,现在我在fun中执行一个比较费时的任务,比如压缩文件。如果不放在线程中,会阻塞ui界面,所以就放到了一个子线程中,到这里也没有问题,现在的问题是,我压缩完后想通知主线程结果,感觉没有办法通知,如果在线程函数中直接调用A.cpp中的某个函数比如ProcResult(),这个无法达到目的,因为cef的相关东西不能在其他线程运行,所以想让子线程怎么通知主线程,在主线程中来调用ProcResult[/quote] 之前有一个场景是这样的 dll里有一个函数1是用来展示输入密码界面的,但是验证这个密码必须在主exe中的函数2中做,所以在主exe中写了一个全局的函数当做回调函数1,这个全局的函数调用了主exe的函数2。在主exe调用dll的函数1时,将回调函数1的地址当做函数1其中的一个参数传给dll,这样dll在获取了用户输入的密码后调用回调函数1,这样就回到了主exe的全局函数,主exe的全局函数调用了主exe的函数2来验证密码是否正确。 不过回调貌似只能在同一进程里搞搞。不通进程就不行了,不过不通进程可以用管道和共享内存啊
starytx 2017-05-17
  • 打赏
  • 举报
回复
经过再三折腾,只能将压缩解压缩操作放到有窗口的应用进程中了,然后要压缩时,渲染进程给窗口进程发消息,窗口进程开线程,传入窗口句柄,线程完后给窗口发消息,窗口再转发到渲染进程。
starytx 2017-05-16
  • 打赏
  • 举报
回复
引用 10 楼 zhao4zhong1 的回复:
多进程参考: Microsoft SDK\samples\winbase\SharedMem\Consumer.Cpp Microsoft SDK\samples\winbase\SharedMem\Makefile Microsoft SDK\samples\winbase\SharedMem\Producer.Cpp Microsoft SDK\samples\winbase\SharedMem\Queue.h Microsoft SDK\samples\winbase\SharedMem\ReadMe.Txt Microsoft SDK\samples\winbase\SharedMem\Common.h
我还是详细描述下我的场景吧 比如有个A.cpp,里边有一些函数,比如fun(),这些代码在cef框架中是运行在渲染进程中的。渲染进程将一个无窗口的exe作为宿主程序,这个exe的main里边就执行一个cef的函数(阻塞的),A.cpp是在一个dll中的,但是我经过查看,可以确定在A.cpp的fun()中GetCurrentThreadId和在exe的main中返回的是相同的值,现在我在fun中执行一个比较费时的任务,比如压缩文件。如果不放在线程中,会阻塞ui界面,所以就放到了一个子线程中,到这里也没有问题,现在的问题是,我压缩完后想通知主线程结果,感觉没有办法通知,如果在线程函数中直接调用A.cpp中的某个函数比如ProcResult(),这个无法达到目的,因为cef的相关东西不能在其他线程运行,所以想让子线程怎么通知主线程,在主线程中来调用ProcResult
starytx 2017-05-16
  • 打赏
  • 举报
回复
引用 7 楼 chen1990720 的回复:
用回调不行吗?
你说的回调是在子线程里调用主线程里的某个函数吗?如果是的话,那就相当于在子线程里执行,而我的结果处理代码不可以在子线程中正确运行,所以我就想子线程通过什么方式通知主线程,然后在主线程中运行结果处理代码
赵4老师 2017-05-16
  • 打赏
  • 举报
回复
多进程参考: Microsoft SDK\samples\winbase\SharedMem\Consumer.Cpp Microsoft SDK\samples\winbase\SharedMem\Makefile Microsoft SDK\samples\winbase\SharedMem\Producer.Cpp Microsoft SDK\samples\winbase\SharedMem\Queue.h Microsoft SDK\samples\winbase\SharedMem\ReadMe.Txt Microsoft SDK\samples\winbase\SharedMem\Common.h
赵4老师 2017-05-16
  • 打赏
  • 举报
回复
任何收发两端速度不一致的通讯,都需要在它们之间使用一个足够大的FIFO缓冲区。 对任何FIFO缓冲区的使用,都需要仔细考虑接收端接收时超时无数据和发送端发送时FIFO缓冲区已满这两种情况下该如何做。 这些概念都在这段经典代码中有所体现。 这段经典代码还包括以下必须考虑的因素: ◆跨Windows和Linux平台 ◆多线程锁 ◆多线程日志 ◆日志文件占用的磁盘空间可控 ◆日志中的时间包括毫秒 ◆传输的数据对应的每个字节到底是几 ◆如何退出多线程程序 ◆……
赵4老师 2017-05-16
  • 打赏
  • 举报
回复
干货(在此论坛也是大路货了)来了——
//循环向a函数每次发送200个字节长度(这个是固定的)的buffer,
//a函数中需要将循环传进来的buffer,组成240字节(也是固定的)的新buffer进行处理,
//在处理的时候每次从新buffer中取两个字节打印
#ifdef _MSC_VER
    #pragma warning(disable:4996)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
    #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 _MSC_VER
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,struct 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 _MSC_VER
    pthread_exit(NULL);
#endif
}
int PutToRBuf(int cn,CRITICAL_SECTION *cs,struct 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 _MSC_VER
    pthread_exit(NULL);
#endif
}
int main() {
#ifdef _MSC_VER
    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 _MSC_VER
    _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 _MSC_VER
    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;
}
天际抓根宝 2017-05-16
  • 打赏
  • 举报
回复
用回调不行吗?
starytx 2017-05-16
  • 打赏
  • 举报
回复
引用 5 楼 cutmelon 的回复:
引用 2 楼 starytx 的回复:
引用 1 楼 cutmelon 的回复:
到底是多进程还是多线程?如果单纯要解决这个cef函数阻塞问题,把它放到一个线程里挂着不行吗?主线程就是控制
可能说了和问题不太想干的信息了,现在就是这个cef框架是由多个进程组成的,主进程是应用程序进程,然后一个页面一个渲染进程,渲染进程是cef自己启动和管理的,依附在上边我贴出的那个exe中(也就是要执行那个阻塞的cef函数),我在渲染进程后台代码(不在这个依附的exe中,但通过打印线程ID,可以确定和这个依附的exe在同一个线程里)中开了一个线程来执行费时的工作,以免界面假死,现在就是不知道这个费时工作完成后如何通知到我
这种情况应该不是怎么通知到你吧,而是你知道结果之后怎么通知那个渲染框架,这应该看看这个框架提供的机制了
差不多是这个意思。搞不明白那个框架的消息循环啊,自己新开的线程,不知道如何通知主线程了,反正调用函数是不行的,等于还是在子线程中执行,不知道除了发送线程消息,还有没有其他机制来通知到主线程
cutmelon 2017-05-16
  • 打赏
  • 举报
回复
引用 2 楼 starytx 的回复:
引用 1 楼 cutmelon 的回复:
到底是多进程还是多线程?如果单纯要解决这个cef函数阻塞问题,把它放到一个线程里挂着不行吗?主线程就是控制
可能说了和问题不太想干的信息了,现在就是这个cef框架是由多个进程组成的,主进程是应用程序进程,然后一个页面一个渲染进程,渲染进程是cef自己启动和管理的,依附在上边我贴出的那个exe中(也就是要执行那个阻塞的cef函数),我在渲染进程后台代码(不在这个依附的exe中,但通过打印线程ID,可以确定和这个依附的exe在同一个线程里)中开了一个线程来执行费时的工作,以免界面假死,现在就是不知道这个费时工作完成后如何通知到我
这种情况应该不是怎么通知到你吧,而是你知道结果之后怎么通知那个渲染框架,这应该看看这个框架提供的机制了
starytx 2017-05-16
  • 打赏
  • 举报
回复
引用 3 楼 zhao4zhong1 的回复:
《Windows核心编程》
老师来点干货啊。我这个的情况是,对线程处理的结果无法在子线程中执行,所以在线程中执行外边的函数是不行的,只能是通过消息通知到主线程,在主线程来执行一些代码,而主线程是以那个无界面的后台程序为宿主的,所以没有办法搞一个循环来GetMessage子线程发来的线程消息,因为如果把循环取消息放在那个cef函数之前,那么页面(CEF是chrome浏览器的框架)根本就显示不了,如果放在那个cef函数后边,又没有作用,因为那个cef函数会阻塞
赵4老师 2017-05-16
  • 打赏
  • 举报
回复
《Windows核心编程》
starytx 2017-05-15
  • 打赏
  • 举报
回复
引用 1 楼 cutmelon 的回复:
到底是多进程还是多线程?如果单纯要解决这个cef函数阻塞问题,把它放到一个线程里挂着不行吗?主线程就是控制
可能说了和问题不太想干的信息了,现在就是这个cef框架是由多个进程组成的,主进程是应用程序进程,然后一个页面一个渲染进程,渲染进程是cef自己启动和管理的,依附在上边我贴出的那个exe中(也就是要执行那个阻塞的cef函数),我在渲染进程后台代码(不在这个依附的exe中,但通过打印线程ID,可以确定和这个依附的exe在同一个线程里)中开了一个线程来执行费时的工作,以免界面假死,现在就是不知道这个费时工作完成后如何通知到我
cutmelon 2017-05-15
  • 打赏
  • 举报
回复
到底是多进程还是多线程?如果单纯要解决这个cef函数阻塞问题,把它放到一个线程里挂着不行吗?主线程就是控制

64,654

社区成员

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

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