linux下c++多线程详解,应用于UDP

本文使用pthread的库,调用其中API可方便实现多线程效果。
本文主要讲解实际中用到的几个接口函数,足够一般开发使用。
实例为应用与UDP协议的收发,打开接收数据线程,接收不影响主线程,主线程进行数据处理等工作,方便二次开发。
关于UDP的教程可以参看:http://blog.csdn.net/weixin_37895339/article/details/72716774
首先介绍需要用到的接口函数。
1.pthread_create()函数
用于创建线程,调用该函数后,线程开始执行。创建成功时返回0。

int pthread_create(pthread_t *thread, const pthread_attr_t, void *(*_function)(void*), void *arg)

参数介绍:

a.第一个参数为线程id的指针,创建方式为:

pthread_t thread[Thread_Num];

将id的地址付给第一个参数:

rc = pthread_create(*thread[i],NULL,NULL,NULL);

b.第二个参数为线程属性设置,创建方式为:

pthread_attr_t attr;       //线程属性设置
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);   //将属性设置为joinable,可以使主线程等待该线程执行完后,再结束主线程
rc = pthread_create(*thread[i],&attr,NULL,NULL);

c.第三个参数为线程执行的函数&第四个参数为该函数需要的参数
该函数类型为 void*,即返回值为void*。参数类型为void*,如果要传递多个参数,可以建立一个结构体进行传递。示例如下:

struct thread_recdata{     //函数所需传递的参数,一共有两个,放在一个结构中
   int  sockfd;     //socket
   char *info;          //接受的数据
};
thread_recdata thread_rec;   //创建函数所用参数
void  *recinfo(void *rec_data);   //创建函数
rc = pthread_create(&thread[0], &attr ,recinfo,(void *)&thread_rec);    //开启线程
pthread_attr_destroy(&attr);   //释放属性attr的空间

2.pthread_join()函数
调用该函数可以阻塞主线程,等待子线程运行完后再结束主线程。如果不阻塞,可能出现主线程运行完,程序结束,但子线程还没运行完的情况。

int pthread_join(pthread_t thread,void **status_value)

d第一个参数为要等待子线程的id,第二个参数为返回的线程状态信息,其类型为void*。实例为:

void *status;
rc = pthread_join(thread[i], &status);
if (rc){
    printf("Error:unable to join");
    exit(-1);
}

3.线程锁
当两个线程同时调用修改同一个数据变量时,必须加线程锁,否则将会出现数据错乱的情况。数据加锁后,其余调用该变量的线程将会被阻塞,直到释放锁。实例如下:

pthread_mutex_t rec_mutex;        //创建线程锁
pthread_mutex_lock(&rec_mutex);     //加锁
rec_queue.push(thread_info->info);    //修改数据
pthread_mutex_unlock(&rec_mutex);    //解锁

下面介绍一个应用于UDP协议的多线程实例:
本例打开一个接受线程不断接受外部发来的数据,主线程处理这些数据,另开一个显示线程用作调试。方便二次开发。

#include
#include
#include
#include
#include
#include
#include 
#include 
#include 
#include 
#include 

#define port_in 12321
#define port_out 12322
#define Num_Thread 3

char info_rec[10][128];

pthread_mutex_t rec_mutex;        //线程锁

struct thread_senddata{
   int  sockfd;     //socket
   char *info;          //发送的数据
   char *addr;         //发送的地址
   int port;             //发送的端口
};

struct thread_recdata{
   int  sockfd;     //socket
   char *info;          //接受的数据
};




int initudp(void)
{
    int sockfd;
    /* Create Socket*/
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(-1==sockfd){
        return 0;
        puts("Failed to create socket");
    }
    /*Config Socket Addr*/
    struct sockaddr_in addr;
    socklen_t          addr_len=sizeof(addr);
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;       // Use IPV4
    addr.sin_port   = htons(port_in);    //
    addr.sin_addr.s_addr = inet_addr("10.106.2.146");
    /* Time out*/
//    struct timeval tv;
//    tv.tv_sec  = 0;
//    tv.tv_usec = 200000;  // 200 ms
//    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval));
    /* Bind Socket*/
    if (bind(sockfd, (struct sockaddr*)&addr, addr_len) == -1){      //收数据才需要bind
        printf("Failed to bind socket on port %d\n", port_in);
        close(sockfd);
        return false;
    }
    return sockfd;
}




void sendinfo(thread_senddata *thread_info)     //发送数据调用
{
    int len;
    struct sockaddr_in dest;
    socklen_t dest_len = sizeof(dest);
    memset(&dest, 0, sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port   = htons(thread_info->port);
    dest.sin_addr.s_addr = inet_addr(thread_info->addr);


    if(strlen(thread_info->info)!=0)               //如果数组有数则发送
    {
        len = strlen(thread_info->info);
        sendto(thread_info->sockfd, thread_info->info, len, 0, (sockaddr*)&dest, dest_len);
    }
}



void  *recinfo(void *rec_data)     //接受线程调用的函数
{
    struct thread_recdata *thread_info;
    thread_info = (struct thread_recdata *)rec_data;
    struct sockaddr_in src;
    socklen_t src_len = sizeof(src);
    memset(&src, 0, sizeof(src));

    while(1)
    {
        int sz = recvfrom(thread_info->sockfd, thread_info->info, 128, 0, (sockaddr*)&src, &src_len);
        if (sz > 0){
            thread_info->info[sz] = 0;

        pthread_mutex_lock(&rec_mutex);
        for(int j =0 ; j < 10; j++)//最多存10个指令,不够后面再修改吧
        {
            if(strlen(info_rec[j])==0)    //给空的地方存
            {
                strcpy(info_rec[j],thread_info->info);
                break;
            }
        }
        pthread_mutex_unlock(&rec_mutex);
        }
    }
}


void *get_info_rec(void *arg)    //显示线程调用的函数
{
    while(1)
    {
        pthread_mutex_lock(&rec_mutex);
        if(strlen(info_rec[0])!=0)
        {
            printf("%s  \n",info_rec[0]);
            for(int i=0;i<9;i++)
            {
                strcpy(info_rec[i],info_rec[i+1]);
            }
            memset(info_rec[9],0,128);
        }
        pthread_mutex_unlock(&rec_mutex);
        //sleep(1);
    }
}


int main(void)
{
    char info[100];    //发送的
    char addr[20];    //发送目标地址
    struct thread_senddata thread_info;    //发送信息函数利用的信息结构体
    char buffer[128];   //接受到的数据,要不要其实无所谓了,后面再修改吧
    int sockfd;
    thread_recdata thread_rec;
    memset(info_rec,0,10*128);

    /*线程所需变量*/
    pthread_t  thread[Num_Thread];     //存储线程的id
    pthread_attr_t attr;       //线程属性设置
    int rc;      //创建线程的返回值,检查是否创建成功
    void *status;

    /*创建UDP*/
    sockfd = initudp();
    if (sockfd==0)
    {
        printf("socket error!");
    }

    /*设置接受线程参数*/
    thread_rec.sockfd = sockfd;
    thread_rec.info = buffer;

    /*创建线程*/
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);

    rc = pthread_create(&thread[0], &attr ,recinfo,(void *)&thread_rec);   //收数据
    if (rc){
      printf("Error:unable to create thread");
     exit(-1);
    }
    rc = pthread_create(&thread[1], &attr ,get_info_rec,NULL);   //显示数据
    if (rc){
      printf("Error:unable to create thread");
     exit(-1);
    }

    /*设置发送的数据*/
    strcpy(info,"$HAKQGS112233");
//  strcpy(addr,"10.106.3.65");
    strcpy(addr,"10.106.2.146");
    thread_info.addr = addr;
    thread_info.info = info;
    thread_info.port = port_out;
    thread_info.sockfd = sockfd;
    while(1)
    {
        sendinfo(&thread_info);
        sleep(1);
        strcpy(info,"$HAYRZT030000");
        sendinfo(&thread_info);
        sleep(1);
        strcpy(info,"$HAYRZT030001");
        sendinfo(&thread_info);
        sleep(1);
        strcpy(info,"$HAYRZT030002");
        sendinfo(&thread_info);
    }



    //删除属性,并等待其他线程
    pthread_attr_destroy(&attr);
    for(int i = 0 ;i < Num_Thread;i++)
    {
          rc = pthread_join(thread[i], &status);
          if (rc){
              printf("Error:unable to join");
             exit(-1);
          }
    }
    pthread_exit(NULL);   //删除线程
    return 1;
}

WALDM

你可能感兴趣的:(C++)