c - _beginthreadex() 返回有效句柄,并在使用 Codeblocks/Mingw 和 GNU GCC 编译器执行线程时崩溃

标签 c multithreading gcc mingw

我在 Windows 环境下使用 Codeblocks/Mingw 和 GNU GCC 编译器编写 C 程序时遇到问题。

我正在尝试实现一个 TCP 服务器库,它允许同时创建和管理多个服务器。

我创建了一些结构来管理服务器:

typedef struct
{
  BOOL bExitThread;
  HANDLE hThread;
}TagThreadControl;

typedef struct
{
  SOCKET sSocket;
  int iMaxReceiveLengthPerMessage;
  struct in_addr tagIPAddress;
  USHORT usPort;
  TagThreadControl tagThread;
  TagQueue *ptagReveivedMessages;
}TagConnection_Internal;

typedef struct
{
  BOOL bInternalProcessingActive;
  UINT uiID;
  SOCKET sSocket;
  TagConnection_Internal *ptagConnections;
  WSADATA tagWsa;
  struct sockaddr_in tagServerInfo;
  TagThreadControl tagThreadGetNewConnections;
  int iMaxBacklog;
  int iMaxConnections;
  int iConnectionCount;
}TagServer;

无论如何,atm 我专注于只运行一个,但在使用函数 _beginthreadex 时遇到了问题。当我调用它时,它返回一个有效的句柄(!NULL)并在启动线程时在内部崩溃。使用以下函数创建一个新服务器:

UINT uiTCPServer_Init_g(unsigned short usDestinationPort,
                        int iMaxReceiveLengthPerMessage,
                        int iMaxConnectionsCount,
                        int iMaxBacklogCount)
{
  UINT uiNewID;
  int iIndex;
  WSADATA tagWsa;

  /* First Server */
  if(iServerCount_m==0)
  {
    if(!bIDGenerator_Init_g(100))
    {
      printf("bIDGenerator_Init_g(): failed\n");
      return(INVALID_SERVER_HANDLE);
    }
    if(!bIDGenerator_GetNewID_g(&uiNewID))
    {
      printf("bIDGenerator_GetNewID_g(): failed\n");
      return(INVALID_SERVER_HANDLE);
    }
    printf("Got ID: %d\n",uiNewID);
    if(!(ptagServer_m=malloc(sizeof(TagServer))))
      return(INVALID_SERVER_HANDLE);

    if(!(ptagServer_m->ptagConnections=malloc(sizeof(TagConnection_Internal)*iMaxConnectionsCount)))
    {
      return(INVALID_SERVER_HANDLE);
    }
    /* Winsock DLL initislisieren */
    if(WSAStartup(MAKEWORD(2,2),&tagWsa)!= 0)
    {
      printf("Init failed with error: %d\n",WSAGetLastError());
      return(INVALID_SERVER_HANDLE);
    }
    printf("Initialised\n");
  }
  else
  {
    //TODO: Implement list, for multiple servers
    printf("**NOT IMPLEMENTED!**\n");
    return(INVALID_SERVER_HANDLE);
  }
  for(iIndex=0;iIndex<iMaxConnectionsCount;++iIndex)
    ptagServer_m[iServerCount_m].ptagConnections[iIndex].iMaxReceiveLengthPerMessage=iMaxReceiveLengthPerMessage;

  /* Create Socket for listening.. */
  if((ptagServer_m[iServerCount_m].sSocket = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET)
  {
    printf("uiTCPServer_Init_g(): Failed to create Socket: %d\n",WSAGetLastError());
    if(iServerCount_m==0)
      WSACleanup();
    return(INVALID_SERVER_HANDLE);
  }
  printf("Socket created\n");   // TODO: remove this

  ptagServer_m[iServerCount_m].tagServerInfo.sin_family = AF_INET;
  ptagServer_m[iServerCount_m].tagServerInfo.sin_addr.s_addr = INADDR_ANY;
  ptagServer_m[iServerCount_m].tagServerInfo.sin_port = htons(usDestinationPort);

  ptagServer_m[iServerCount_m].iMaxBacklog=iMaxBacklogCount;
  ptagServer_m[iServerCount_m].iMaxConnections=iMaxConnectionsCount;

  /* Socket binden */
  if(bind(ptagServer_m[iServerCount_m].sSocket,
          (struct sockaddr*)&ptagServer_m[iServerCount_m].tagServerInfo,
          sizeof(ptagServer_m[iServerCount_m].tagServerInfo)) == SOCKET_ERROR)
  {
    printf("Bind failed: %d\n",WSAGetLastError());
    if(iServerCount_m==0)
      WSACleanup();
    return(INVALID_SERVER_HANDLE);
  }
  printf("Bind done\n");   // TODO: remove this
  ptagServer_m[iServerCount_m].uiID=uiNewID;
  ++iServerCount_m;

  return(uiNewID);

这是创建后调用的函数,该函数在调用 _beginthreadex 时崩溃:

BOOL bTCPServer_StartListening_g(UINT uiServerID)
{
UINT uiThreadID;
TagServer *ptagCurrServer=ptagGetServerByID_m(uiServerID);
if(!ptagCurrServer)
  return(FALSE);

/* Start listen on socket */
if(listen(ptagCurrServer->sSocket,
          ptagCurrServer->iMaxBacklog) == SOCKET_ERROR)
{
  printf("listen(): failed\n");
  return(FALSE);
}
printf("listen on socket started...\n");   // TODO: remove this
ptagCurrServer->tagThreadGetNewConnections.bExitThread=FALSE;
if(!(ptagCurrServer->tagThreadGetNewConnections.hThread=(HANDLE)_beginthreadex(NULL,
                                                                               0,
                                                                               &Thread_GetNewConnections_m,
                                                                               (void*)ptagCurrServer,
                                                                               0,
                                                                               &uiThreadID)))
{
  printf("_beginthreadex(): failed starting Thread_GetNewConnections_m");
  return(FALSE);
}
printf("_beginthreadex() returned valid handle\n");   // TODO: remove this
Sleep(2000); //Without that Sleep, returns successful and crashes after
printf("started listening thread\n");   // TODO: remove this
return(TRUE);
}

新线程中调用的函数如下所示:

unsigned __stdcall Thread_GetNewConnections_m(void *pvParam)
{
TagServer *ptagCurrServer=(TagServer*)pvParam;
struct sockaddr_in tagClientInfo;
int iSocketSize=sizeof(struct sockaddr_in);
int iFreeConnectionIndex;
UINT uiThreadID;

if(!ptagCurrServer)
{
  printf("Thread_GetNewConnections_m(): Terminated in an unusual way\n");
  return(0);
}
printf("started Thread_GetNewConnections_m()...\n");   // TODO: remove this
memset(ptagCurrServer->ptagConnections,0,sizeof(TagConnection_Internal)*ptagCurrServer->iMaxConnections);
while(!ptagCurrServer->tagThreadGetNewConnections.bExitThread)
{
  printf("Getnewcons...\n");   // TODO: remove this
  vCleanUpDeadConnections_m(ptagCurrServer);
  // TODO: clean up dead connections here...
  if(ptagCurrServer->iConnectionCount >= ptagCurrServer->iMaxConnections)
  {
    printf("Max Connections reached\n");
    Sleep(100);
    continue;
  }
  if((iFreeConnectionIndex=iTCPServer_GetNextFreeConnectionIndex_m(ptagCurrServer->ptagConnections,ptagCurrServer->iMaxConnections)) <0)
  {
    printf("iTCPServer_GetNextFreeConnectionIndex_m(): failed (Should not happen)\n");
    Sleep(100);
    continue;
  }
  printf("next free connection index: %d\n",iFreeConnectionIndex);
  if((ptagCurrServer->ptagConnections[iFreeConnectionIndex].sSocket=accept(ptagCurrServer->sSocket,(struct sockaddr*)&tagClientInfo,&iSocketSize)) == INVALID_SOCKET)
  {
    printf("accept(): failed\n");   // TODO: Don't return, handle error somehow
    Sleep(10);
    continue;
  }
  printf("New connection established\n");
  ++ptagCurrServer->iConnectionCount;
  /* Store Data from client */
  memcpy(&ptagCurrServer->ptagConnections[iFreeConnectionIndex].tagIPAddress,&tagClientInfo.sin_addr,sizeof(struct in_addr));
  ptagCurrServer->ptagConnections[iFreeConnectionIndex].usPort=ntohs(tagClientInfo.sin_port); //Convert form Network to host short
  /* Start Thread for new Connection */
  if((ptagCurrServer->ptagConnections[iFreeConnectionIndex].tagThread.hThread=(HANDLE)_beginthreadex(NULL,
                                                                                                     0,
                                                                                                     Thread_ConnectionHandler_m,
                                                                                                     &ptagCurrServer->ptagConnections[iFreeConnectionIndex],
                                                                                                     0,
                                                                                                     &uiThreadID))==NULL)
  {
    printf("_beginthreadex(): failed to start Thread for new connection\n");
    --ptagCurrServer->iConnectionCount;
    closesocket(ptagCurrServer->ptagConnections[iFreeConnectionIndex].sSocket);
    Sleep(100);
    continue;
  }
  Sleep(10);
}
return(0);
}

有趣的是,每当我在这个函数中注释整个代码(不包括 return(0))并且只在那里留下一个 printf() 时,程序仍然崩溃,甚至没有进入该函数。我包含了以下头文件,其中一些是我自己创建的:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <process.h>
#include <windows.h>
#include <winsock2.h>

如果我尝试运行编译后的程序,跟踪将如下所示:

Curr index 0 (0), used: FALSE
Got ID: 1
Initialised
Socket created
Bind done
listen on socket started...
_beginthreadex() returned valid handle

使用线程是否需要任何其他编译器标志/头文件...?

如果需要更多信息,请告诉我。

问候,XXXBold

最佳答案

我解决了这个问题,另一个错误调用 malloc() 的函数损坏了内存,可以使用 Dr Memory 解决问题

关于c - _beginthreadex() 返回有效句柄,并在使用 Codeblocks/Mingw 和 GNU GCC 编译器执行线程时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41650864/

相关文章:

用汇编语言编写的c调用函数

c - 读取文本文件的精确列并将值/文本放入 vector 中

c++ - OpenGL 三角形邻接索引

c++ - 我可以报告 openmp 任务的进度吗?

c++ - 使用 gcc 链接 Fortran 和 C++ 二进制文件

C 指定字节长度的读写问题

java - 在 ThreadLocal 实例中获取 volatile 变量的目的

c# - 从多个线程异步写入文件c#

c++ - MacOS 的 "-std=gnu++0x"选项

c++ - 如何从 FILE* 获取 std::ifstream 对象