免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3902 | 回复: 11

[C] 多进程+多线程问题 [复制链接]

论坛徽章:
0
发表于 2008-07-09 21:20 |显示全部楼层
写了个测试程序,大概作的事情是这样:
1.  主进程启动5个子进程,主进程循环等待。
2.  每个进程再启动两个线程,并循环等待。
3.  线程不断写信息到日志文件。

代码如下:
#include <iostream>
#include <string>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

using namespace std;

string logfile="./test.log";

// 写日志函数
int WriteLog(const char *filename,const char *message,...)
{
    time_t timer;
    struct tm *tblock;
    FILE *logfile;
    char FNAME[128];
    int year;
    va_list ap;
    char Tmp_buff[1024];

    timer=time(NULL);
    tblock=localtime(&timer);
    year=tblock->tm_year+1900;

    strcpy(FNAME,"");
    sprintf(FNAME,"%s.%02d%02d",filename,tblock->tm_mon+1,tblock->tm_mday);
    if ((logfile=fopen(FNAME,"a"))==NULL)
    {
        return -1;
    }
    va_start(ap, message);
    memset(Tmp_buff,0,1024);
    vsnprintf (Tmp_buff,1023,message, ap);

    fprintf(logfile,"[%04d%02d%02d %02d:%02d:%02d]%s\n",year,tblock->tm_mon+1,
           tblock->tm_mday,tblock->tm_hour,tblock->tm_min,tblock->tm_sec,Tmp_buff);
    fflush(logfile);
    fclose(logfile);
    va_end(ap);
    return 1;
}

void* SendThreadPack(void * args);
void* RecvThreadPack(void * args);

class CTestClass
{
public:
    CTestClass(){};
    ~CTestClass(){};
    int Run();
        
private:
    pthread_mutex_t mutex_tm;
    pthread_mutex_t mutex_log;

public:
    void SendThread();
    void RecvThread();

};

void* SendThreadPack(void * args)
{        
    ((CTestClass*)args)->SendThread();
     return NULL;
}

void* RecvThreadPack(void * args)
{
    ((CTestClass*)args)->RecvThread();
     return NULL;
}

int CTestClass::Run()
{
    pthread_mutex_init(&mutex_tm, NULL);
    pthread_mutex_init(&mutex_log, NULL);

    pthread_t send_pid = 0;
    pthread_t recv_pid = 0;
    pthread_attr_t      SendThreadAttr;
    pthread_attr_t      RecvThreadAttr;

    pthread_attr_init( &SendThreadAttr);
    pthread_attr_init( &RecvThreadAttr);

    pthread_attr_setdetachstate( &SendThreadAttr, PTHREAD_CREATE_DETACHED);
    pthread_attr_setdetachstate( &RecvThreadAttr, PTHREAD_CREATE_DETACHED);

    WriteLog(logfile.c_str(),"[pid=%d]**********开始创建线程",getpid());
        
    int ret = -1;
    ret = pthread_create( &send_pid, &SendThreadAttr,SendThreadPack , this);
    if (ret != 0)
    {
        WriteLog(logfile.c_str(),"[pid=%d]创建发送线程失败,ret=%d",getpid(),ret);
        return -1;
    }

    ret = pthread_create( &recv_pid, &RecvThreadAttr,RecvThreadPack , this);
    if (ret != 0)
    {
        WriteLog(logfile.c_str(),"[pid=%d]创建接收线程失败,ret=%d",getpid,ret);
        return -1;
    }
        
    WriteLog(logfile.c_str(),"[pid=%d]发送/接收线程创建成功[send_pid=%d,recv_pid=%d]",
         getpid(),send_pid,recv_pid);
   
    while (1)
    {
        int n = pthread_kill(send_pid,0);
        int m = pthread_kill(recv_pid,0);
        WriteLog(logfile.c_str(),
            "$$$$$$$$$$$$$$$[pid=%d]发送进程 sleep(5)n=%d,m=%d",getpid(),n,m);
        usleep(5000000);
    }
   
    WriteLog(logfile.c_str(),"===== 总计: s 条");
    return 0;
}

void CTestClass::SendThread()
{
    WriteLog(logfile.c_str(),"**********[pid=%d] 发送线程创建,开始工作",thread_self());
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    while (1)
    {
        pthread_testcancel();
        WriteLog(logfile.c_str(),
           "**********[pid=%d|发送线程]工作中.........................",thread_self());
        sleep(2);
    }
   
    WriteLog(logfile.c_str(),"**********[pid=%d] 发送线程退出",thread_self());
}

void CTestClass::RecvThread()
{
    WriteLog(logfile.c_str(),"**********[pid=%d] 接收线程创建,开始工作",thread_self());
   
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    while (1)
    {
        pthread_testcancel();
        WriteLog(logfile.c_str(),
           "**********[pid=%d|接收线程]工作中.........................",thread_self());
        sleep(2);
     }
   
    WriteLog(logfile.c_str(),"**********[pid=%d] 接收线程退出",thread_self());
}

int createSendThread(int s)
{
    pid_t pid=1;

    pid = fork();
    if (pid == 0)
    {//子进程
         WriteLog(logfile.c_str(),
            "[i=%d|pid=%d]--send_run 开始.-----------------------------------",s,getpid());
         CTestClass sendSms;
         sendSms.Run();
         WriteLog(logfile.c_str(),
            "[i=%d|pid=%d]--send_run 结束.-----------------------------------",s,getpid());
         exit(1);
    }
     else if(pid > 0)
     {//父进程
         fprintf(stderr,"father\n");
     }
     else
     {//fork出错
          WriteLog(logfile.c_str(),"父进程:fork出错.");
          return -1;
    }
    return 0;
}

//==============================================================================
// Main()
//==============================================================================
int main()
{
    for (int i = 0; i < 5; i++)
    {
         createSendThread(i);
    }
        
    while (1)
    {
          WriteLog(logfile.c_str(),"父进程:等待.");
          sleep(10);
    }
        
    return 0;
}

该程序我在AIX Version 5上编译通过,运行后输出的日志见附件。
我想问的是:
1.  从日志输出来看,两个线程创建成功,但为什么线程函数中的信息没有写到日志里?
2.  pthread_kill检测两个线程是合法的,但为什么5个子进程中创建的线程ID都是一样的?

test.rar

797 Bytes, 下载次数: 35

论坛徽章:
0
发表于 2008-07-09 21:22 |显示全部楼层
这个帖子发的很辛苦,麻烦强人指点.....

为方便大伙调试,特附源码文件,下载编译即可。

多谢了.............!!!

main.rar

1.64 KB, 下载次数: 76

论坛徽章:
0
发表于 2008-07-09 21:27 |显示全部楼层
1、不同的线程操作同一个文件要加锁。
2、这个问题可能是上面那个问题引起的,因为你是根据日志来判断线程id的,而你的这个写日志函数并不是线程安全的。

论坛徽章:
0
发表于 2008-07-09 21:43 |显示全部楼层
原帖由 wwwsq 于 2008-7-9 21:27 发表
1、不同的线程操作同一个文件要加锁。
2、这个问题可能是上面那个问题引起的,因为你是根据日志来判断线程id的,而你的这个写日志函数并不是线程安全的。


按照你说的“多个线程操作同一个文件要加锁”,我已经改了写日志的WriteLog函数,如下:
int WriteLog(const char *filename,const char *message,...)
{
    time_t timer;
    struct tm *tblock;
    FILE *logfile;
    char FNAME[128];
    int year;
    va_list ap;
    char Tmp_buff[1024];

                pthread_cleanup_push((void(*) (void *))pthread_mutex_unlock, (void *)&mutex_log);
    pthread_mutex_lock(&mutex_log);
    timer=time(NULL);
    tblock=localtime(&timer);
    year=tblock->tm_year+1900;

    strcpy(FNAME,"");
    sprintf(FNAME,"%s.%02d%02d",filename,tblock->tm_mon+1,tblock->tm_mday);
    if ((logfile=fopen(FNAME,"a"))==NULL)
    {
        return -1;
    }
    va_start(ap, message);
    memset(Tmp_buff,0,1024);
    vsnprintf (Tmp_buff,1023,message, ap);

    fprintf(logfile,"[%04d%02d%02d %02d:%02d:%02d]%s\n",
            year,tblock->tm_mon+1,tblock->tm_mday,tblock->tm_hour,tblock->tm_min,tblock->tm_sec,Tmp_buff);
    fflush(logfile);
    fclose(logfile);
    pthread_mutex_unlock(&mutex_log);
    pthread_cleanup_pop(0);
    va_end(ap);
    return 1;
}

但编译后,输出依旧......

论坛徽章:
0
发表于 2008-07-09 21:56 |显示全部楼层
自己顶下,辛苦发的帖子还没解决,别沉了......!

论坛徽章:
0
发表于 2008-07-09 22:21 |显示全部楼层
原帖由 chinaljj 于 2008-7-9 21:43 发表


按照你说的“多个线程操作同一个文件要加锁”,我已经改了写日志的WriteLog函数,如下:
int WriteLog(const char *filename,const char *message,...)
{
    time_t timer;
    struct tm *tblock;
  ...



1,mutex_log有没有初始化
2,检查一下pthread_mutex_lock成功与否
3,不要调用pthread_cleanup_push和pthread_cleanup_pop

论坛徽章:
0
发表于 2008-07-09 22:36 |显示全部楼层
原帖由 wwwsq 于 2008-7-9 22:21 发表



1,mutex_log有没有初始化
2,检查一下pthread_mutex_lock成功与否
3,不要调用pthread_cleanup_push和pthread_cleanup_pop


大哥,按照你的吩咐,改了代码如下:
#include <iostream>
#include <string>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

using namespace std;

void* SendThreadPack(void * args);
void* RecvThreadPack(void * args);

class CTestClass
{
public:
        CTestClass(){};
        ~CTestClass(){};
        int Run();
        void setP(string &strFile)
        {
                m_strFile = strFile;
        }
       
private:
        pthread_mutex_t mutex_tm;
        pthread_mutex_t mutex_log;
        string m_strFile;
       
        int WriteLog(const char *filename,const char *message,...);

public:
  void SendThread();
  void RecvThread();

};

void* SendThreadPack(void * args)
{       
  ((CTestClass*)args)->SendThread();
   return (void *)NULL;
}

void* RecvThreadPack(void * args)
{
  ((CTestClass*)args)->RecvThread();
   return (void *)NULL;
}

// 写日志函数
int CTestClass::WriteLog(const char *filename,const char *message,...)
{
    time_t timer;
    struct tm *tblock;
    FILE *logfile;
    char FNAME[128];
    int year;
    va_list ap;
    char Tmp_buff[1024];

                //pthread_cleanup_push((void(*) (void *))pthread_mutex_unlock, (void *)&mutex_log);
    int s;
    s = pthread_mutex_lock(&mutex_log);
    fprintf(stderr,"pthread_mutex_lock=%d\n",s);
    timer=time(NULL);
    tblock=localtime(&timer);
    year=tblock->tm_year+1900;

    strcpy(FNAME,"");
    sprintf(FNAME,"%s.%02d%02d",filename,tblock->tm_mon+1,tblock->tm_mday);
    if ((logfile=fopen(FNAME,"a"))==NULL)
    {
        fprintf(stderr,"aaaaaaa\n");
        return -1;
    }
    va_start(ap, message);
    memset(Tmp_buff,0,1024);
    vsnprintf (Tmp_buff,1023,message, ap);

    fprintf(logfile,"[%04d%02d%02d %02d:%02d:%02d]%s\n",
            year,tblock->tm_mon+1,tblock->tm_mday,tblock->tm_hour,tblock->tm_min,tblock->tm_sec,Tmp_buff);
    fflush(logfile);
    fclose(logfile);
    s = pthread_mutex_unlock(&mutex_log);
    fprintf(stderr,"pthread_mutex_unlock=%d\n",s);
    //pthread_cleanup_pop(0);
    va_end(ap);
    return 1;
}

int CTestClass::Run()
{
  int s;
  s = pthread_mutex_init(&mutex_tm, NULL);
  fprintf(stderr,"pthread_mutex_init(tm)=%d\n",s);
  s = pthread_mutex_init(&mutex_log, NULL);
        fprintf(stderr,"pthread_mutex_init(log)=%d\n",s);

  pthread_t send_pid = 0;
  pthread_t recv_pid = 0;
  pthread_attr_t      SendThreadAttr;
  pthread_attr_t      RecvThreadAttr;

  s = pthread_attr_init( &SendThreadAttr);
  fprintf(stderr,"pthread_attr_init(SendThreadAttr)=%d\n",s);
  s = pthread_attr_init( &RecvThreadAttr);
        fprintf(stderr,"pthread_attr_init(RecvThreadAttr)=%d\n",s);

  pthread_attr_setdetachstate( &SendThreadAttr, PTHREAD_CREATE_DETACHED);
  pthread_attr_setdetachstate( &RecvThreadAttr, PTHREAD_CREATE_DETACHED);

        WriteLog(m_strFile.c_str(),"[pid=%d]**********开始创建线程",getpid());
       
        int ret = -1;
  ret = pthread_create( &send_pid, &SendThreadAttr,&SendThreadPack , this);
  if (ret != 0)
  {
                WriteLog(m_strFile.c_str(),"[pid=%d]创建发送线程失败,ret=%d",getpid(),ret);
          return -1;
        }

  ret = pthread_create( &recv_pid, &RecvThreadAttr,&RecvThreadPack , this);
        if (ret != 0)
  {
                WriteLog(m_strFile.c_str(),"[pid=%d]创建接收线程失败,ret=%d",getpid,ret);
                return -1;
        }
        
  WriteLog(m_strFile.c_str(),"[pid=%d]发送/接收线程创建成功[send_pid=%d,recv_pid=%d]",
                  getpid(),send_pid,recv_pid);
   
        while (1)
  {
                int n = pthread_kill(send_pid,0);
    int m = pthread_kill(recv_pid,0);
    WriteLog(m_strFile.c_str(),"$$$$$$$$$$$$$$$[pid=%d]发送进程sleep(5)n=%d,m=%d",getpid(),n,m);
    usleep(5000000);
        }
   
  WriteLog(m_strFile.c_str(),"===== 总计: s 条");
  return 0;
}

void CTestClass::SendThread()
{
        WriteLog(m_strFile.c_str(),"**********[pid=%d] 发送线程创建,开始工作",thread_self());
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  while (1)
  {
          pthread_testcancel();
    WriteLog(m_strFile.c_str(),"**********[pid=%d|发送线程]工作中.........................",thread_self());
    sleep(2);
        }
   
  WriteLog(m_strFile.c_str(),"**********[pid=%d] 发送线程退出",thread_self());
}

void CTestClass::RecvThread()
{
        WriteLog(m_strFile.c_str(),"**********[pid=%d] 接收线程创建,开始工作",thread_self());
   
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
  while (1)
  {
          pthread_testcancel();
                WriteLog(m_strFile.c_str(),"**********[pid=%d|接收线程]工作中.........................",thread_self());
                sleep(2);
        }
   
  WriteLog(m_strFile.c_str(),"**********[pid=%d] 接收线程退出",thread_self());
}

int createSendThread(int s,string &logFile)
{
        pid_t pid=1;

        pid = fork();
        if (pid == 0)
        {//子进程
                //WriteLog(logfile.c_str(),"[i=%d|pid=%d]--send_run 开始.-----------------------------------",s,getpid());
                CTestClass sendSms;
                sendSms.setP(logFile);
                sendSms.Run();
                //WriteLog(logfile.c_str(),"[i=%d|pid=%d]--send_run 结束.-----------------------------------",s,getpid());
                exit(1);
        }
        else if(pid > 0)
        {//父进程
            fprintf(stderr,"father\n");
        }
        else
        {//fork出错
                //WriteLog(logfile.c_str(),"父进程:fork出错.");
                return -1;
        }
        return 0;
}

//==============================================================================
// Main()
//==============================================================================
int main()
{
        string logfile="./test.log";
        //pthread_mutex_init(&mutex_log, NULL);
        for (int i = 0; i < 5; i++)
        {
                createSendThread(i,logfile);
        }
       
        while (1)
        {
                //WriteLog(logfile.c_str(),"父进程:等待.");
                fprintf(stderr,"父进程:等待.");
                sleep(10);
        }
       
        return 0;
}

可线程中的输出在日志文件里还是看不到.............能否再指点指点.....

论坛徽章:
0
发表于 2008-07-09 22:46 |显示全部楼层

回复 #7 chinaljj 的帖子

在gdb里面,b CTestClass::WriteLog

然后每次进这个函数的时候 p pthread_self()看看打印出来是什么。

论坛徽章:
0
发表于 2008-07-09 22:48 |显示全部楼层
原帖由 chinaljj 于 2008-7-9 21:43 发表


按照你说的“多个线程操作同一个文件要加锁”,我已经改了写日志的WriteLog函数,如下:
int WriteLog(const char *filename,const char *message,...)
{
    time_t timer;
    struct tm *tblock;
  ...


多进程追加写同一个文件也是需要加锁来限制的。这个就不是pthread_mutex_lock能解决的了。

但是主要问题不是这个。

线程ID在不同的进程中,可以是一样的吧。因此,线程号一样有什么不对的?

论坛徽章:
0
发表于 2008-07-10 09:38 |显示全部楼层
我增加了一个全局变量:
static mmm;

在进入两个线程后分别加1,并在线程所属的子进程中输出,但输出的全是0,说明线程根本就没运行,这是为什么?
线程没运行,但 pthread_kill(send_id,0)却返回0,这又是为什么?

期待中......
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP