【问题标题】:Thread in C not waiting as expectedC中的线程没有按预期等待
【发布时间】:2013-05-30 02:12:06
【问题描述】:

在我的主函数中,我创建了一个执行 pingOMS 函数的线程。以下是从我的主要功能中提取的代码。

if (status = pthread_create(&agentPingThread,NULL,(void *) &pingOMS, NULL) != 0 ){
    LogError("%s: Failed to create the OM agent ping thread -- %s\n", prog,
strerror(status));        
}

此 pingOMS 函数通过调用 pingOMS 函数中的另一个函数 ThreadWait1 来强制当前线程等待,每 10 秒使用套接字与服务器联系。函数 ThreadWait1 使用 pthread_cond_timedwait 来实现这一点。以下是 pingOMS 的代码:

int pingOMS(){
DEBUG("Inside %s %s() \n",__FILE__,__func__);

if(This.stopped || failedPings > 1){
    DEBUG("  Ping manager stopping ...\n");
    return TRUE;
}

int socketPING,returnHB;
returnHB = FALSE;
struct sockaddr_in serverADDRESS;
struct hostent *hostINFO;    
char remoteFILE[4096],recvBUFF[4096];

if ((hostINFO = gethostbyname(This.servername)) == NULL){
    failedPings++;
    LogError("Ping manager unable to reach OM Server.\n");
    if(failedPings < 2) goto SKIP_POINT1;        
    if(failedPings > 1){
        This.stopped = TRUE;
        return FALSE;
    }
}

if ( (socketPING = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    failedPings++;
    LogError("Ping manager unable to create socket.\n");
    if(failedPings < 2) goto SKIP_POINT1;        
    if(failedPings > 1){
        This.stopped = TRUE;
        return FALSE;            
    }
}

serverADDRESS.sin_family = hostINFO->h_addrtype;
memcpy((char *) &serverADDRESS.sin_addr.s_addr, hostINFO->h_addr_list[0], hostINFO-
>h_length);
serverADDRESS.sin_port = htons((int) This.serverport);

if (connect(socketPING, (struct sockaddr *) &serverADDRESS, sizeof(serverADDRESS)) < 0) {
    failedPings++;
    LogError("Ping manager unable to connect OM Server on port %d\n",
 (int)This.serverport);
    if(failedPings < 2) goto SKIP_POINT2;        
    if(failedPings > 1){
        This.stopped = TRUE;
        close(socketPING);
        return FALSE;            
    }
}else{
    DEBUG("  Ping manager successfully connected to OM Server on port 
%d\n",This.serverport);
}

sprintf(remoteFILE,"STARTPING|%d|%s|ENDPING",This.agentID,getOracleDate());    

if (send(socketPING, remoteFILE, sizeof(remoteFILE), 0) >= 0){
    DEBUG("  Server ping initiated.\n");
}else{
    LogError("Server ping failed. OM agent has lost connection to OM server.\n");
    failedPings++;    
    if(failedPings < 2) goto SKIP_POINT2;
    if(failedPings > 1){
        This.stopped = TRUE;
        close(socketPING);
        return FALSE;
    }
}                 


// Start - Following code interpret server ping status sent by OM server
int fr_block_sz = 0;
recvBUFF[0] = 0;
    while((fr_block_sz = recv(socketPING, recvBUFF, sizeof(recvBUFF), 0)) > 0){
        returnHB = TRUE;
        DEBUG("  Receiving ping data from OM server.\n");
    }       
    DEBUG("  Received buffer %s\n",recvBUFF);
    if(returnHB == TRUE){
        if(!strncmp(recvBUFF,"SUCCESS",7)) {   
            DEBUG("  Server ping succeeded.\n");                
        }        
        else{
            LogError("OM agent has lost connection with OM server and will shutdown.\n");
            failedPings++;
            if(failedPings < 2) goto SKIP_POINT2;
            if(failedPings > 1){
                This.stopped = TRUE;
                close(socketPING);
                return FALSE;
            }
        }                        
}else{
            failedPings++;
            LogError("OM agent has not received heartbeat from server.\n");
            if(failedPings < 2) goto SKIP_POINT2;
            if(failedPings > 1){
                This.stopped = TRUE;
                close(socketPING);
                return FALSE;
            }
        }

//End
SKIP_POINT2:       
close(socketPING);  
DEBUG("  Agent ping thread going into sleep mode ... \n");
SKIP_POINT1:
ThreadWait1(10000);
pingOMS();

}

这是 ThreadWait1 的代码:

void ThreadWait1(int timeInMSec)
{
DEBUG("Inside %s %s() \n",__FILE__,__func__); 
int rt;
pthread_mutexattr_t mtx_attr;
pthread_mutex_t mtx;
pthread_condattr_t cond_attr;
pthread_cond_t cond;

int milliseconds;

pthread_mutexattr_init ( &mtx_attr );
//pthread_mutexattr_settype ( &mtx_attr, PTHREAD_MUTEX_NORMAL );
pthread_mutexattr_setpshared ( &mtx_attr, PTHREAD_PROCESS_PRIVATE );

pthread_mutex_init ( &mtx, &mtx_attr );
pthread_mutexattr_destroy ( &mtx_attr );

#ifdef USE_CONDATTR
pthread_condattr_init ( &cond_attr );
if ( pthread_condattr_setclock ( &cond_attr, CLOCK_REALTIME ) != 0 )
{
    fputs ( "pthread_condattr_setclock failed", stderr );
    exit ( EXIT_FAILURE );
}

pthread_cond_init ( &cond, &cond_attr );
pthread_condattr_destroy ( &cond_attr );
#else
pthread_cond_init ( &cond, NULL );
#endif

    struct timespec now, ts;
        clock_gettime ( CLOCK_REALTIME, &now );

    ts.tv_sec = now.tv_sec + timeInMSec / 1000;
        ts.tv_nsec = now.tv_nsec + (timeInMSec % 1000) * 1000000;
    if (ts.tv_nsec > 1000000000)
    {
        ts.tv_nsec -= 1000000000;
        ++ts.tv_sec;
    }

    DEBUG ( " %ld.%09ld %ld.%09ld \n", now.tv_sec, now.tv_nsec,
             ts.tv_sec, ts.tv_nsec );

    pthread_mutex_lock ( &mtx );
    rt = pthread_cond_timedwait ( &cond, &mtx, &ts );
    ASSERT(rt);

    pthread_mutex_unlock ( &mtx );

}

问题:

线程只等待 4 ~ 5 秒而不是 10 秒,但非常有趣的是,当独立 c 程序中的 ThreadWait1 函数的相同逻辑时,它运行良好。它可能与CPU上的线程调度或其他东西有关。

【问题讨论】:

  • 为什么不直接调用sleep(10)pingOMS() 让线程休眠10 秒?
  • pthread_cond_timedwait() 返回了什么?对于正常返回,应该返回 0,这应该会绊倒你的 ASSERT()
  • 另外(尽管可能与您的问题无关),ThreadWait1() 永远不会清理 mtxcond(与 pthread_mutex_destroy() 等)

标签: c pthreads


【解决方案1】:

这不是问题的答案,而是我心中的疑问。您使用的是什么平台?

其次,为什么你创建了一个递归调用,我认为 ThreadWait1 应该在每 X 次(在你的情况下为 10 秒)后调用 pingOMS 函数。

试试下面的代码:

#include <unistd.h>


if (status = pthread_create(&agentPingThread,NULL,(void *) &ThreadWait1, NULL) != 0 ){
    LogError("%s: Failed to create the OM agent ping thread -- %s\n", prog,
strerror(status));        
}


void ThreadWait1()
{
    int timeInMSec = 10;
    while(1)
    {
        pingOMS();
        // Add your locks here if required
        sleep(timeInMSec);
        // release the locks if locked
    }
}

并删除 pingOMS();从 pingOMS() 函数调用,使其不会调用自身(无递归)

【讨论】:

  • 它的 32 位 linux 内核为 2.6.18-194.17.1.0.1.el5。我的 ThreadWait1 函数只会导致当前线程等待。如果我不递归调用 pingOMS 函数,那么在等待 10 秒后 pingOMS 函数将完成并且不会尝试另一个 ping。
  • 是的,我的意思是创建一个连续运行的线程 ThreadWait1(即 while(1) )并将线程休眠 10 秒,然后调用 pingOMS。您当前的方法可能会导致内存不足错误。因为函数调用永远不会完成。这也可能是您的问题的根本原因
  • 我尝试在 ThreadWait1 中调用 pingOMS,但行为没有改变。你认为我应该创建另一个函数 pingThread,它将有一个 while(1) 循环调用 pingOMS,然后调用 ThreadWait1。类似于while(1){pingOMS(); ThreadWait1(10000);}。然后我的主函数将创建类似pthread_create(&amp;agentPingThread,NULL,(void *) &amp;pingThread, NULL) 的线程。我在 C 编程方面不是那么好,所以我提前道歉有些事情没有意义。
  • 非常感谢,这有效,但想知道为什么 pthread_cond_timedwait 表现异常。我将在整个项目中严重依赖这些 pthread_cond_timedwait 函数,尤其是当睡眠函数不接受毫秒时。
  • 对于毫秒,您可以使用 nanosleep 如下:nanosleep((struct timespec[]){{0, 500000000}}, NULL); 这将使其休眠半秒
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-15
  • 2018-05-05
  • 1970-01-01
  • 2015-05-06
  • 1970-01-01
  • 2022-01-06
相关资源
最近更新 更多