Windows下多线程编程技术及其实现(转载)

CAN开发笔记(TI开发者推荐笔记) 查阅了很多资料没有查阅到关于5728芯片CAN模块寄存器的介绍,希望通过本文能给做CAN驱动的后来者有一点参考意义,我也是刚接触CAN模块有些不足请各位多多指正。 由下图所示是CAN模块初始化流程图 首先要开始初始化,设置CAN位时间,然后配置message objects, 完成初始化。 1.开始初始化 首先要控制DCAN_CTL 寄存器,该寄存器是CAN模块的总控制器,很多配置通过... 阅读详情

本文首先讨论16位Windows下不具备的线程的概念,然后着重讲述在32位Windows 95环境下多线程的编程技术,最后给出利用该技术的一个实例,即基于Windows95下TCP/IP的可视电话的实现。

  一、问题的提出

  作者最近在开发基于Internet网上的可视电话过程中,碰到了这样一个问题。在基于Internet网上的可视电话系统中,同时要进行语音采集、语音编解码、图象采集、图象编解码、语音和图象 码流的传输, 所有的这些事情,都要并行处理。特别是语音信号,如果进行图象编解码时间过长,语音信号得不到服务,通话就有间断,如果图象或语音处理时间过长,而不能及时的传输码流数据,通信同样也会中断。这样就要求我们实现一种并行编程,在只有一个CPU的机器上,也就是要将该CPU时间按照一定的优先准则分配给各个事件,定期处理某一事件而不会在某一事件处理过长,在32位Windows95或WindowsNT下,我们可以用多线程的编程技术来实现这种并行编程。实际上这种并行编程在很多场合下都是必须的。例如,在FileManager拷贝文件时,它显示一个对话框, 列出源文件和目标文件的名称,并在对话框中包含了一个Cancel按钮。如果在文件拷贝过程中,点中Cancel按钮,就会终止拷贝。

  在16位Windows中,实现这类功能需要在FileCopy循环内部周期性地调用PeekMessage函数。如果正在读一个很大的数据块,则只有当这个块读完以后才能响应这个按钮动作,如果从软盘读文件,则要花费好几秒的时间,由于机器反应太迟钝,你会频繁地点中这个按钮,以为系统不知道你想终止这个操作。如果把FileCopy指令放入另外一个线程,你就不需要在代码中放一大堆PeekMessage函数,处理 用户界面的线程将与它分开操作,这样,点中Cancel按钮后会立即得到响应。同样的道理,在应用程序中创建一个单独线程来处理所有打印任务也是很有用的,这样,用户可以在打印处理时继续使用应用程序。

  二、线程的概念

  为了了解线程的概念,我们必须先讨论一下进程的概念。

  一个进程通常定义为程序的一个实例。在Win32中, 进程占据4GB的地址空间。与它们在MS-DOS和16位Windows操作系统中不同, Win32进程是没有活力的。这就是说,一个Win32进程并不执行什么指令,它只是占据着4GB的地址空间,此空间中有应用程序EXE文件的 代码和数据。EXE需要的任意DLL也将它们的代码和数据装入到进程的地址空间。除了地址空间,进程还占有某些资源,比如文件、动态内存分配和线程。当进程终止时,在它生命期中创建的各种资源将被清除。

  但是进程是没有活力的,它只是一个静态的概念。为了让进程完成一些工作,进程必须至少占有一个线程,所以线程是描述进程内的执行,正是线程负责执行包含在进程的地址空间中的代码。实际上,单个进程可以包含几个线程, 它们可以同时执行进程的地址空间中的代码。为了做到这一点,每个线程有自己的一组CPU寄存器和堆栈。

  每个进程至少有一个线程在执行其地址空间中的代码,如果没有线程执行进程 地址空间中的代码, 进程也就没有继续存在的理由,系统将自动清除进程及其地址空间。为了运行所有这些线程,操作系统为每个独立线程安排一些CPU 时间,操作系统以轮转方式向线程提供时间片,这就给人一种假象,好象这些线程都在同时运行。创建一个Win32进程时,它的第一个线程称为主线程,它 由系统自动生成,然后可由这个主线程生成额外的线程,这些线程,又可生成更多的线程。

三、线程的编程技术

  1、编写线程函数

  所有线程必须从一个指定的函 数开始执行,该函数称为线程函数,它必须具有下列原型:

  DWORDWINAPIYourThreadFunc(LPVOIDlpvThreadParm);

  该函数输入一个LPVOID型的参数,可以是一个DWORD型的整数,也可以是一个指向一个缓冲区的指针, 返回一个DWORD型的值。象WinMain函数一样,这个函数并不由操作系统调用, 操作系统调用包含在KERNEL32.DLL中的非C运行时的一个内部函数,如StartOfThread,然后由StartOfThread函数建立起一个异常处理框架后,调用我们的函数。

  2、创建一个线程

  一个进程的主线程是由操作系统自动生成,如果你要让一个主线程创建额外的线程,你可以调用来CreateThread完成。

  HANDLECreateThread(LPSECURITY_ATTRIBUTES lpsa,DWORDcbstack,LPTHREAD_START_ROUTINElpStartAddr,
  LPVOID lpvThreadParm,DWORDfdwCreate,LPDWORDlpIDThread);

  其中lpsa参数为一个指向SECURITY_ATTRIBUTES结构的指针。如果想让对象为缺省安全属性的话,可以传一个NULL,如果想让任一个子进程都可继承一个该线程对象句柄,必须指定一个SECURITY_ATTRIBUTES结构,其中bInheritHandle成员初始化为TRUE。参数cbstack表示线程为自己所用堆栈分配的地址空间大小,0表示采用系统缺省值。

  参数lpStartAddr用来表示新线程开始执行时代码所在函数的地址,即为线程函数。lpvThreadParm为传入线程函数的参数,fdwCreate参数指定控制线程创建的附加标志,可以取两种值。如果该参数为0,线程就会立即开始执行,如果该参数为CREATE_SUSPENDED,则系统产生线程后,初始化CPU,登记CONTEXT结构的成员,准备好执行该线程函数中的第一条指令,但并不马上执行,而是挂起该线程。最后一个参数lpIDThread 是一个DWORD类型地址,返回赋给该新线程的ID值。

  3、终止线程

  如果某线程调用了ExitThread 函数,就可以终止自己。

  VOIDExitThread(UINTfuExitCode );

  这个函数为调用该函数的线程设置了退出码fuExitCode后, 就终止该线程。调用TerminateThread函数亦可终止线程。

  BOOLTerminateThread(HANDLE hThread,DWORDdwExitCode);

  该函数用来结束由hThread参数指定的线程, 并把dwExitCode设成该线程的退出码。当某个线程不在响应时,我们可以用其他线程调用该函数来终止这个不响应的线程。

  4、设定线程的相对优先级

  当一个线程被首次创建时,它的优先级等同于它所属进程的优先级。在单个进程内可以通过调用SetThreadPriority函数改变线程的相对优先级。一个线程的优先级是相对于其所属的进程的优先级而言的。

  BOOLSetThreadPriority(HANDLE hThread,intnPriority);

  其中参数hThread是指向待修改 优先级线程的句柄,nPriority可以是以下的值:

  THREAD_PRIORITY_LOWEST,
  THREAD_PRIORITY_BELOW_NORMAL,
  THREAD_PRIORITY_NORMAL,
  THREAD_PRIORITY_ABOVE_NORMAL,
  THREAD_PRIORITY_HIGHEST

  5、挂起及恢复线程

  先前我提到过可以创建挂起状态的线程(通过传递CREATE_SUSPENDED标志给函数CreateThread来实现)。当你这样做时,系统创建指定线程的核心对象,创建线程的栈,在CONTEXT结构中初始化线程CPU注册成员。然而,线程对象被分配了一个初始挂起计数值1,这表明了系统将不再分配CPU去执行线程。要开始执行一个线程,另一个线程必须调用ResumeThread并传递给它调用CreateThread时返回的线程句柄。

  DWORD ResumeThread(HANDLEhThread);

  一个线程可以被挂起多次。如果一个线程被挂起3次, 则该线程在它被分配CPU之前必须被恢复3次。除了在创建线程时使用CREATE_SUSPENDED标志,你还可以用SuspendThread函数挂起线程。

  DWORDSuspendThread(HANDLE hThread); 

四、多线程编程技术的应用

  我在前面说过,为了实现基于TCP/IP下的可视电话,就必须“并行”地执行语音采集、语音编解码、图象采集、图象编解码以及码流数据的接收与发送。语音与图象的采集由硬件采集卡进行,我们的程序只需初始化该硬件采集卡,然后实时读取采集数据即可,但语音和图象数据的编解码以及码流数据的传输都必须由程序去协调执行,决不能在某一件事件上处理过长,必须让CPU轮流的为各个事件服务,Windows95下的线程正是满足这种要求的编程技术。

  下面我给出了利用Windows95 环境下的多线程编程技术实现的基于TCP/IP的可视电话的部分源码,其中包括主窗口过程函数,以及主叫端与被叫端的TCP/IP接收线程函数和语音编解码的线程函数。由于图象编解码的实时性比语音处理与传输模块的实时性的 要求要低些,所以我以语音编解码为事件去查询图象数据,然后进行图象编解码,而没有为图象编解码去单独实现一个线程。

  在主窗口初始化时, 我用CREATE_SUSPENDED标志创建了两个线程hThreadG7231和hThreadTCPRev。一个用于语音编解码,它的线程函数为G723Proc, 该线程不断查询本地有无编好码的语音和图象的码流,如有,则进行H.223打包,然后通过TCP的端口发送给对方。另外一个线程用于TCP/IP的接收,它的线程函数为AcceptThreadProcRev,该线程不断侦 测TCP/IP端口有无对方传来的码流,如有,就接收码流,进行H.223解码后送入相应的缓冲区。该缓冲区的内容,由语音编解码线程G723Proc查询,并送入相应的解码器。由于使用了多线程的编程技术,使得操作系统定时去服务语 音编解码模块和传输模块,从而保证了通信的不中断。

  五、程序源码

 

//基于TCP/IP可视电话主窗口的窗口过程
LONG APIENTRY MainWndProc(HWND hWnd,UINT message,UINT wParam, LONG lParam)
{
 static HANDLE hThreadG7231,hThreadTCPListen,hThreadTCPRev;
 DWORDThreadIDG7231,ThreadIDTCPListen,ThreadIDTCPRev;
 static THREADPACK tp;
 static THREADPACK tp1;
 unsigned char Buf[80];
 CAPSTATUS capStatus;
 switch (message)
  {
   case WM_CREATE:
     Init_Wsock(hWnd); //初始化一些数据结构
     Init_BS(2,&bs);
     vd_tx_pdu.V_S = 0;vd_tx_pdu.N_S = 0;
     vd_rx_pdu.V_R = 0;vd_tx_sdu.bytes = 0;
     if( dnldProg ( hWnd, "h324g723.exe") )
      {
       //装入语音编解码的DSP核心
       MessageBox(hWnd,"Load G.723.1 Kernel Error","Error",MB_OK);
       PostQuitMessage(0); }
     else
       MessageBox(hWnd,"Load G.723.1 Kernel OK!","Indication",MB_OK);
     //创建语音编解码的线程
     parag7231.hWnd = hWnd;
     hThreadG7231=CreateThread (NULL, 0,(LPTHREAD_START_ROUTINE)G723Proc,
                   (G7231DATA *)?g7231,
                   CREATE_SUSPENDED,(LPDWORD)&ThreadIDG7231);
     if (!hThreadG7231)
      {
       wsprintf(Buf, "Error in creating G7231 thread: %d",GetLastError());
       MessageBox (hWnd, Buf, "WM_CREATE", MB_OK);}
     //创建TCP/IP接收线程
     tp1.hWnd = hWnd;
     hThreadTCPRev = CreateThread (NULL, 0,(LPTHREAD_START_ROUTINE)AcceptThreadProcRev,
                    (G7231DATA *)&tp1,CREATE_SUSPENDED,
                    (LPDWORD)&ThreadIDTCPRev);
     if (!hThreadTCPRev)
      {
       wsprintf(Buf, "Error in creating TCP Receive thread: %d",GetLastError());
       MessageBox (hWnd, Buf, "WM_CREATE", MB_OK);}
     //开始侦听网络
     SendMessage(hWnd,WM_COMMAND,IDM_LISTEN,NULL);
     break;
   case WM_VIDEO_ENCODE: //图象编码
     if(needencode)EncodeFunction(hWnd);
     needencode = SendVideoToBuff(&vd_tx_sdu, buff);
     frameMode=TRUE;
     capPreview(capWnd,FALSE);
     capOverlay(capWnd,FALSE);
     capGrabFrameNoStop(capWnd);
     break;
   case WM_VIDEO_DECODE: //图象解码
     Video_Decod_begin = 1;
     play_movie();
     Video_Decod_begin = 0;
     break;
   case WM_COMMAND:
     switch(LOWORD(wParam))
      {
       case IDM_CONNECT: //响应对方的呼叫,接通可视电话
         WskConnect( hWnd );
         ResumeThread(hThreadTCPRev); //运行TCP/IP接收线程
         ResumeThread(hThreadG7231); //运行语音编解码线程
         BeginG7231Codec(); //初始化图象采集卡,并开始采集图象
         frameMode = FALSE;
         capWnd = capCreateCaptureWindow((LPSTR)"Capture Window",
                          WS_CHILD | WS_VISIBLE,
                          100, 100, 176,144 ,
                          (HWND) hWnd, (int) 0);
         capSetCallbackOnError(capWnd, (FARPROC)ErrorCallbackProc) ;
         capSetCallbackOnStatus(capWnd, (FARPROC)StatusCallbackProc) ;
         capSetCallbackOnFrame(capWnd, (FARPROC)FrameCallbackProc) ;
         capDriverConnect(capWnd, 0);
         CenterCaptureWindow(hWnd, capWnd);
         capDlgVideoSource(capWnd);
         capDlgVideoFormat(capWnd);
         capDlgVideoCompression(capWnd);
         capGetStatus(capWnd,&capStatus,sizeof(CAPSTATUS));
         StartNewVideoChannel(hWnd, capWnd) ;
         image = image_one;
         frameMode = TRUE;
         capPreview(capWnd,FALSE);
         capOverlay(capWnd,FALSE);
         capGrabFrameNoStop(capWnd);
         break;
       case IDM_LISTEN: //拨对方号码,呼叫对方
         sock = socket( AF_INET, SOCK_STREAM, 0);
         if (sock == INVALID_SOCKET) {
          MessageBox(hWnd, "socket() failed", "Error", MB_OK);
          closesocket(sock);
          break;}
         if (!FillAddr(hWnd, &local_sin, FALSE )) //获取TCP/IP地址和端口号
          break;
         EnableMenuItem(GetMenu( hWnd ), IDM_LISTEN, MF_GRAYED);
         SetWindowText( hWnd, "Waiting for connection..");
         bind ( sock , (struct sockaddr FAR *)&local_sin,sizeof(local_sin);
         if (listen( sock, MAX_PENDING_CONNECTS ) <0)
          {
           sprintf(szBuff, "%d is the error",
               WSAGetLastError()); MessageBox(hWnd, szBuff, "listen(sock) failed",
               MB_OK);
           break;}
         tp.hWnd="hWnd; //开始本地的TCP/IP接收线程"
         _beginthread(AcceptThreadProc,0,&tp);
         ResumeThread(hThreadG7231); // 开始本地语音编解码的线程
         break;
       case IDM_DISCONNECT: //挂断可视电话
         CloseG7231Codec();
         SuspendThread(hThreadG7231);
         SuspendThread(hThreadTCPRev);
         WSACleanup();
         Init_Video_Decod_Again();
         capSetCallbackOnError(capWnd, NULL);
         capSetCallbackOnStatus(capWnd, NULL);
         InvalidateRect(hWnd,NULL,1); capSetCallbackOnFrame(capWnd, NULL);
         capSetCallbackOnVideoStream(capWnd, NULL);
         capDriverDisconnect(capWnd);
         Init_Wsock(hWnd);
         MessageBox(hWnd, "Now closing the Video telephone","",MB_OK);
         SetDisConnectMenus(hWnd);
         SendMessage(hWnd, WM_COMMAND,IDM_LISTEN,NULL);
         break;
       case IDM_EXIT:
         CloseG7231Codec();
         SendMessage(hWnd, WM_CLOSE, 0, 0l);
         break; default:
      return (DefWindowProc(hWnd, message, wParam, lParam));
      }
      break;
    case WM_CLOSE:
      if (IDOK !="MessageBox(" hWnd, "OK to close window?", gszAppName,
                  MB_ICONQUESTION | MB_OKCANCEL ))break ;
    case WM_DESTROY:
      WSACleanup();
      CloseG7231Codec();
      TerminateThread(hThreadG7231,0);
      TerminateThread(hThreadTCPRev,0);
      capSetCallbackOnError(capWnd, NULL);
      capSetCallbackOnStatus(capWnd, NULL);
      capSetCallbackOnFrame(capWnd, NULL);
      capSetCallbackOnVideoStream(capWnd, NULL);
      capDriverDisconnect(capWnd);
      FreeAll();
      PostQuitMessage(0);
      break;
   default: /* Passes it on if unproccessed */
       return (DefWindowProc(hWnd, message, wParam, lParam));
   }
 return (0);
}

//主叫方TCP/IP接收线程
DWORD WINAPI AcceptThreadProc( PTHREADPACK ptp )
{
 SOCKADDR_IN acc_sin; /* Accept socket address internet style */
 int acc_sin_len; /* Accept socket address length */
 int status;
 acc_sin_len="sizeof(acc_sin);"
 //调用阻塞函数accept,一直到远端响应为止
 sock="accept(" sock,(struct sockaddr FAR *) &acc_sin,(int FAR *) &acc_sin_len );
 if (sock < 0)
  {
   sprintf(szBuff, "%d is the error", WSAGetLastError());
       MessageBox(ptp->hWnd, szBuff, "accept(sock) failed", MB_OK);
   return (1);
  }
 SetConnectMenus( ptp->hWnd ); //远端提机,可视电话接通
 BeginG7231Codec();
 while (1)
  {
   beg1:
    status = recv((SOCKET)sock, r_mux_buf,MY_MSG_LENGTH, NO_FLAGS_SET );
   if (status == SOCKET_ERROR) {
    status = WSAGetLastError();
    if( status == 10054 ){
     MessageBox(ptp->hWnd,"对方挂断电话","Indication", MB_OK);
     SendMessage( ptp->hWnd, WM_COMMAND,IDM_DISCONNECT,NULL);
     _endthread();
     return (1);
     }
    goto beg1;
    }
   if (status) {
     r_mux_buf[ status ] = '/0';
     if ( r_mux_buf_filled == 1 )
      r_mux_buf_overwrite = 1;
     else
     r_mux_buf_filled = 1;
     r_mux_buf_length = status;
    }
   else
    {
     MessageBox( hWnd, "Connection broken", "Error", MB_OK);
     SendMessage( ptp->hWnd, WM_COMMAND,IDM_DISCONNECT,NULL);
     _endthread();
     return (2);
    }
   demux(); //线路码流H.223解码
   }
 return (0);
}

//被叫方TCP/IP接收线程
DWORD WINAPI AcceptThreadProcRev( PTHREADPACK ptp )
{
 int status;
 while (1)
  {
  beg2:
  status = recv((SOCKET)sock, r_mux_buf,MY_MSG_LENGTH, NO_FLAGS_SET );
  if (status == SOCKET_ERROR)
   {
    status =WSAGetLastError();
    if( status == 10054 )
     {
      MessageBox(ptp->hWnd,"对方挂断电话","Indication", MB_OK);
      SendMessage( ptp->hWnd, WM_COMMAND,IDM_DISCONNECT,NULL);
      return (1);
     }
    goto beg2;
    }
  if (status)
   {
    r_mux_buf[ status ] = '/0';
    if( r_mux_buf_filled == 1 )
     r_mux_buf_overwrite = 1;
    else
     r_mux_buf_filled = 1;
     r_mux_buf_length = status;
   }
  else
   {
    MessageBox( hWnd, "Connection broken", "Error", MB_OK);
    SendMessage( ptp->hWnd, WM_COMMAND,IDM_DISCONNECT,NULL);
    return (2);
   }
  demux();
 } /* while (forever) */
 return (0);
}

//语音编解码线程
DWORD WINAPI G723Proc(G7231DATA *data)
{
 int i,len;
 Audio_tx_pduad_tx_pdu;
 unsigned char mux[MAX_MUX_PDU_SIZE];
 do
  {
   len = 0;
   //检测本地有无语音,图象码流要传输
   i = DetectAudioVideoData();
   switch(i)
    {
     case AUDIO_ONLY: //只有语音码流
       AL2_CRC_coder(&ad_tx_sdu,&ad_tx_pdu);
       //H.223打包
       len = AL2_To_MUX(&ad_tx_pdu, mux);
       break;
     case VIDEO_ONLY: //只有图象码流
       SDU_To_PDU(&vd_tx_sdu,&vd_tx_pdu);
       tx_AL3_I_PDU(&vd_tx_pdu ,&bs , 1); //H.223打包
       len = AL3_To_MUX(&vd_tx_pdu,mux);
       break;
     case AUDIO_VIDEO: //语音和图象码流
       AL2_CRC_coder(&ad_tx_sdu,&ad_tx_pdu);
       SDU_To_PDU(&vd_tx_sdu,&vd_tx_pdu);
       tx_AL3_I_PDU(&vd_tx_pdu ,&bs , 1);
       //H.223打包
       len = AL2_AL3_To_MUX(&ad_tx_pdu,&vd_tx_pdu,mux);
       break;
     case NO_AUDIO_VIDEO: //此刻无码流要传输
       break;
    }
   //TCP/IP发送码流
   if(len != 0)
   send((SOCKET)sock,mux,len,0);
   //是否接收到待解码的码流,有就调用解码器
   PutVideoStreamToDecod();
  }
 while(1);
 return (0);
}



 

华为od 面试八股文_前端_02_含答案 阅读详情

相关推荐

【VisualStdio】手把手教你做一个上位机(1)控件设计布局

网上有很多形形色色的制作上位机教程,有些写的挺好的,但是过于单调。

m0_73409202的博客 5436

Windows C++ 多线程编程示例

/* 题目:主线程创建两个辅助线程,辅助线程1使用选择排序算法对数组的前半部分排序,辅助线程2使用选择排序算法对数组的后半部分排序,主线程等待辅助线程运行結束后,使用归并排序算法归并子线程的计算结果 开发工具:DEV windows平台 语言:C++ */ #include <windows.h> #include <iostream> using namespace std; #define MAX 100 //数组空间最大值 int array[MAX]; //待排

Alkali!的博客 5490

英特尔SVS:十亿级向量搜索的硬件优化与LVQ压缩实战

向量搜索作为处理高维嵌入数据的核心技术,其核心原理是通过近似最近邻(ANN)算法在海量数据中快速找到相似项,以解决传统暴力搜索在规模上的瓶颈。这项技术的核心价值在于为推荐系统、图像检索、自然语言处理等AI应用提供高效的相似性匹配能力,尤其在RAG架构中成为连接非结构化数据与大语言模型的关键基础设施。面对十亿级数据带来的内存与算力挑战,局部自适应向量量化(LVQ)等压缩技术通过减少存储开销并保持精度,而硬件层面的深度优化则利用AVX-512等指令集大幅提升计算效率。本文聚焦于英特尔开源的Scalable Ve

weixin_42526310的博客 553

多线程编程10例

进程和线程都是操作系统的概念。进程是应用程序的执行实例,每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成,进程在运行过程中创建的资源随着进程的终止而被销毁,所使用的系统资源在进程终止时被释放或关闭。线程是进程内部的一个执行单元。系统创建好进程后,实际上就启动执行了该进程的主执行线程,主执行线程以函数地址形式,比如说main或WinMain函数,将程序的启动点提供给Windows系统。主执行线程终止了,进程也就随之终止。

1164

AI Olympics:面向真实决策的不完全信息博弈评测框架

在人工智能落地实践中,传统基准测试(如MMLU、GSM8K)擅长评估知识调用与静态推理能力,却难以衡量模型在动态、模糊、高代价的真实场景中的策略决策水平。AI Olympics正是为弥补这一断层而生——它以扑克、狼人杀等社会性博弈为载体,系统考察模型在不完全信息下的对手建模、欺骗检测、多步序贯推理与代价敏感执行等核心能力。其技术价值在于将‘黑箱决策’转化为可追踪、可归因、可压力测试的动态思维图谱(DTG),支撑金融风控、智能客服、交通调度等强交互业务场景的能力诊断与持续优化。

weixin_30983965的博客 298

杂记 | 使用keycloak实现SSO单点登录(新手向,概念、原理、逻辑、详细步骤、难点解释)

使用keycloak实现SSO单点登录(概念、原理、逻辑、详细步骤、难点解释)

野生猿林仔的博客 2万+

Windows下多线程编程技术及其实现

  本文首先讨论16位Windows下不具备的线程的概念,然后着重讲述在32位Windows 95环境下多线程的编程技术,最后给出利用该技术的一个实例,即基于Windows95下TCP/IP的可视电话的实现。   一、问题的提出   作者最近在开发基于Internet网上的可视电话过程中,碰到了这样一个问题。在基于Internet网上的可视电话系统中,同时要进行语音采集、语音编解码、图象采...

weixin_30692143的博客 233

从零到一:基于Blazor和Elsa Workflows的工作流系统开发实战

本文详细介绍了如何利用Blazor和Elsa Workflows构建高效的工作流系统,从技术选型到生产环境部署,涵盖动态工作流建模、Blazor前端集成及性能优化等核心内容。通过实战案例,展示如何实现订单处理系统的自动化与灵活性,提升企业流程效率。

weixin_26875109的博客 428

【C语言】Windows下的C语言线程编程详解

C语言,线程。

风高秋月白,雨霁晚霞红 7284

《从0到1:CTFer成长之路》书籍配套题目-[第二章 web进阶]文件上传

[第二章 web进阶]文件上传开始行动绕过第1个限制绕过第2个限制 介绍:记录一下笔记,方便以后迅速回忆使用。 《从0到1:CTFer成长之路》书籍配套题目,来源网站:《从0到1:CTFer成长之路》 先看一下题目源码: <?php header("Content-Type:text/html; charset=utf-8"); // 每5分钟会清除一次目录下上传的文件 require_once('pclzip.lib.php'); if(!$_FILES){ echo '

weixin_46703850的博客 3411

【医学图像处理】X-ray成像之X射线的产生

【医学图像处理】X-ray成像之X射线的产生 概述 电流流过钨丝,并将其加热。 随着加热,增加的能量使电子能够通过热电子发射从灯丝中释放出来。 电子被吸引到带正电的阳极,并以由管电位(电压)确定的最大能量撞击钨靶。 当电子轰击目标时,它们通过轫致辐射和特有的相互作用将能量转换为热量(99%)和X射线光子(1%)。 X射线光子以一束能量(X射线光谱)从光束中释放出来,构成X射线图像形成的基础。 设备 阴极 灯丝 用细的(0.2毫米)钨丝制成,因为钨: 原子序数高(A 184,Z 74) 是良好的热

ZhangPY的专栏 2357

C++多线程编程(真实入门)

https://blog.youkuaiyun.com/Kprogram/article/details/89472995

hanxiaoyong_的博客 2669

【AI 编程工具】Codex配置部署指南

目录一、环境准备与基础安装1. 系统兼容性检查2. 前置依赖安装3. 安装方式选择二、API密钥配置与认证1. 获取API密钥2. 配置文件设置3. 临时配置方式三、沙盒环境配置与安全策略1. 沙盒模式选择2. 安全最佳实践四、高级功能配置1. 模型上下文协议(MCP)配置2. 模型版本切换3. 自定义网关配置五、常见问题排查1. 安装失败2. API调用失败3. 处理速度慢4. 配置文件不生效六、生产环境部署建议macOS/Linux:官方提供稳定支持,推荐使用原生环境Windows:官方标注为实验性支持

以实战经验介绍行业知识 2893

(转载)win32多线程的性能

Win32 多线程的性能出处:MicrosoftRuediger R. AscheMicrosoft Developer Network 技术小组 摘要本文讨论将单线程应用程序重新编写成多线程应用程序的策略。它以Microsoft Windows 95和Windows NT的平台为例,从吞吐量(throughput)和响应方面,与兼容的单线程计算相比较而分析了多线程计算的性能。介绍在您

星光中的灯 4069

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

在C++Builer中多线程的实现(转载)

在C++Builer中多线程的实现 Yinyin   还在Dos时代,人们就在寻求一种多任务的实现。于是出现了TSR类型的后台驻留程序,比较有代表性的有Side Kick、Vsafe等优秀的TSR程序,这类程序的出现和应用确实给用户使用计算机带来了极大的方便,比如Side Kick,我们编程可以在不用进编辑程序的状态下,一边编辑源程序,一边编译运行,非常方便。但是,Dos单任务操作系统的致命缺陷注

825

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

转载:c++builder多线程程序

1. 创建多线程程序:  首先,先介绍一下实现多线程的具体步骤。在C++Builder中虽然用Tthread对象说明了线程的概 念,但是Tthread对象本身并不完整,需要在TThread下新建其子类,并重载Execute方法来使用线程对象。在C++Builder下可以很 方便地实现这一点。  在C++Builder IDE环境下选择菜单File|New,在New栏中选中Thread Object

zhtq301的专栏 2189

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

如何使用Robocopy多线程功能加速Windows 10中的文件复制(转载)

此时,许多精通技术的 Windows 用户都会使用 Robocopy(Robust File Copy,强大的文件复制),这是一个内置于 Windows 10 中的命令行工具,它提供了更多功能来帮助用户更快地将数据移动到不同的位置。Robocopy 最为特殊也经常被忽略的是其支持多线程的能力,允许我们同时复制多个文件,而不像在「文件管理器」中复制文件时只能一次一个(移动多个文件时也只是列队之后一个一个移动)。我个人推荐使用 32 个线程,虽然可开的线程可以更多,但数字越大,所使用的系统资源和带宽就越多。

bodybo的专栏 4603

windows lua 多线程 线程同步

今天在改一个程序,改成部分逻辑用lua写,这个程序是多线程的。将程序中部分逻辑改成lua之后,各种非法访问内存错误,各种奇奇怪怪的问题,不分时间,不分地点的出现崩溃。从调用堆栈来看,基本都是使用lua造成的。在多线程中使用lua_newthread得到的lus_State仍然有时候程序会崩溃。基本上可以确定为多线程中操作lua 的问题了。 前几天我转载的一篇文章,文章写了关于lua多线程的作法。...

weixin_34240657的博客 238

多线程、方便扩展的Windows服务程序

多线程、方便扩展的Windows服务程序 吴剑 2012-06-02 原创文章,转载必需注明出处:http://www.cnblogs.com/wu-jian/ 前言 在项目应用中经常会碰到定时调度的工作,比如我曾经开发一个日访问量超过1000W的网站,如果这1000W访问都从数据库读取数据显示给用户,我的服务器肯定承受不了,于是我需要每10分钟把首页生成一次.html的静态文...

weixin_30920597的博客 541

Windows CE下的多线程编程实验(转载自Stone& Ice)

Windows CE多线程编程包括线程的启动、线程的运行状态控制、线程同步及数据通信和线程的正常/非正常退出。本项目的软件及架构在多线程设计上,要求通过多线程实现异步的数据采集及绘制,以提高系统运行效率。 1.       线程的启动Win32API提供支持多线程的启动,调用API函数CreateThread()分配资源启动线程,并返回线程句柄(Handle),以控制线程状态。客观上,

gooogleman#foxmail.com 1905

(转载)Win32 多线程的性能

Win32 多线程的性能Ruediger R. AscheMicrosoft Developer Network 技术小组 摘要本文讨论将单线程应用程序重新编写成多线程应用程序的策略。它以Microsoft Windows 95和Windows NT的平台为例,从吞吐量(throughput)和响应方面,与兼容的单线程计算相比较而分析了多线程计算的性能。介绍在您所能够找到的有关多线程的资料

无限天空 1347

转载----实现FTP多线程下载

 http://publishblog.blogchina.com/blog/tb.b?diaryID=3790095现在有不少软件可实现多线程下载.如NetAnts,JetCar等,其实多线程下载的原理并不复杂,主要的两项技术就是多线程和断点下载。程序中开启多个线程,每个线程利用断点下载,分别下载文件的不同部分,下载完后合并,就可以了。多线程编程很多书已有介绍,这里不再重复,关于断点下载,MFC

tanghuaan的专栏 558

vc6多线程-转载

一、问题的提出编写一个耗时的单线程程序:  新建一个基于对话框的应用程序SingleThread,在主对话框IDD_SINGLETHREAD_DIALOG添加一个按钮,ID为IDC_SLEEP_SIX_SECOND,标题为“延时6秒”,添加按钮的响应函数,代码如下:void CSingleThreadDlg::OnSleepSixSecond() { Sleep(6000); //

lang_113的专栏 1487

Windows环境下使用MFC进行多线程编程(C++)

转载请标明出处:http://blog.youkuaiyun.com/zhangxingping Windows环境下使用MFC进行多线程编程(C++) 进程和线程 (Process andThread) 进程指的是计算机程序的一次执行,或者说是程序执行的一个实例。进程中包含有程序代码及其当前的活动。线程指的是进程中的一个执行路径。一个进程有可能是由多个线程组成,这些线程并发地执行程序指令。   在

每天进步一点点。 7579

【转载】linux和windows下的信号量

将win32程序关于多线程的内容移植到Linux下面,不能简单的按照函数对应来移植。不过通过下面的对应关系,再加上你对这些模式的深入了解,相信会移植的很成功。   信号量   Windows 信号量是一些计数器变量,允许有限个线程/进程访问共享资源。Linux POSIX 信号量也是一些计数器变量,可以用来在 Linux 上实现 Windows 上的信号量功能。   信号量的类型:...

dingyi1774的博客 611

linux windows 多线程编程,windows多线程编程_c语言 windows 多线程_linux多线程编程实例...

Windows多线程编程总结关键字:多线程线程同步线程池内核对象1 内核对象1 .1内核对象的概念内核对象是内核分配的一个内存块,这种内存块是一个数据结构,表示内核对象的各种特征。并且只能由内核来访问。应用程序若需要访问内核对象,需要通过操作系统提供的函数来进行,不能直接访问内核对象(Windows从安全性方面来考虑的)。内核对象通过Create*来创建,返回一个用于标识内核对象的句柄,这些句柄(...

weixin_39957951的博客 142
上一篇: 浅谈C/C++内存泄漏及其检测工具
下一篇: 半透明及透明位图的实现技术
JamesXing
博客等级 码龄20年 30粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值