简单的Linux多线程编程

前言

最近在实习的公司做一个ROS系统,有个部分需要控制电机,以及分析电机码盘给上来的数据,用的是串口通信。
由于码盘给上来的数据时间是不固定的,下放命令的时间也是不固定的,所以只能做成异步通信的形式。所以就需要用到多线程编程了。
编程语言是C,但由于另一个部分是企业提供的,C++形式,用到了很多类,所以这里编译用的是g++

这篇博客里写的只是个demo,实现了线程的功能,加上串口通信的在
http://blog.youkuaiyun.com/u013793399/article/details/52315657

下面这个代码本来是另一个实习生在网上找来的,但是他说跑起来有乱码的现象。我把代码拿过来之后连编译都过不去,后来搞了好几个小时才搞通,顺便找到了乱码的原因,也是有点坑在里面的,所以特地记录下来。

代码

太长不看的同学可以直接copy下面的代码,亲测能跑

//main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <pthread.h>
#include <sys/time.h>

#define MAX 2
pthread_t thread[2];
pthread_mutex_t mut;
int fd;

int set_port(int fd,int  nbits)
{
    struct termios newtio,oldtio;
    if(tcgetattr(fd,&oldtio)!=0)
    {
        perror("pei zhi cuo wu1\n");
        return -1;
    }

    bzero(&newtio,sizeof(newtio)); //清零
    newtio.c_cflag |=CLOCAL|CREAD;//用于本地连接和接收使能

    newtio.c_cflag &=~CSIZE;//设置数据位
    switch(nbits)
    {
    case 7:
        newtio.c_cflag |=CS7;break;
    case 8:
        newtio.c_cflag |=CS8;break;
    }

    //设置奇校验位
        newtio.c_cflag |=PARENB;

    //设置波特率
        cfsetispeed(&newtio,B115200);
        cfsetospeed(&newtio,B115200);

        //设置停止位
        newtio.c_cflag &=~PARENB;

        if((tcsetattr(fd,TCSANOW,&newtio))!=0)
        {
            perror("pei zhi cuo wu2\n");
            return -1;
        }

        printf("mistakes over \n");
        return 0;
    }


void *thread1(void*)
{
    int i;
    printf ("thread1 \n");
    for( i=0;i<MAX;i++){
        pthread_mutex_lock(&mut);
        if(i==0){
            printf("writing  times: %d\n",i+1);
            char buf1[]="12\r\n\0";
            int length=4;//sizeof(buf1); //5-1=4, '\0' shall not be transmitted
            int j=write(fd,buf1,length);
        printf("Writen message: ");
            puts(buf1);
        printf("\n");
            if(j<0)printf("fa song shi bai\n");
            printf("Writen length: %d   \n",j);
        }
        else if(i==1){
            printf("writing times: %d\n",i+1);
            char buf2[]="Jacksen2\r\n\0";
            int length=10;//sizeof(buf2);
            int j=write(fd,buf2,length);
        printf("Writen message: ");
            puts(buf2);
        printf("\n");
            if(j<0)printf("fa song shi bai\n");
            printf("Writen length: %d   \n",j);

                }
        sleep(1);
        pthread_mutex_unlock(&mut);
    }
    printf("thread1 stop\n");
    pthread_exit(NULL);

    }


void *thread2(void*)
{
    int j;
        sleep(1);
        printf("thread2\n");
        char buf[100] = {'\0'};
        for (j = 0; j< MAX; j++)
        {
        pthread_mutex_lock(&mut);
        sleep(1);
        printf("read  %d\n",j+1);
        int k=read(fd,buf,100);
        printf("k+%d\n",k);
        puts(buf);
        pthread_mutex_unlock(&mut);
        sleep(1);
        }
        printf("thread2 Stop\n");
        pthread_exit(NULL);

}


void thread_create(void)
 {
    int temp;
     memset(thread, 0, 2*sizeof(thread));          //comment1
      /*创建线程*/
     if((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0)       //comment2
      printf("xian chegn 1 faile\n");
      else
       printf("X1send surcess\n");

       if((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0)  //comment3
         printf("2 faile\n");
       else
            printf("X2recend surcess\n");
        }



void thread_wait(void)
{
        /*等待线程结束*/
        if(thread[0] !=0) {                   //comment4
                pthread_join(thread[0],NULL);
                printf("thread1 stop \n");
        }
        if(thread[1] !=0) {                //comment5
                pthread_join(thread[1],NULL);
                printf("thread2 stop \n");
        }
}


int main(void) {
        int i,j,k;
        fd=open("/dev/ttyUSB0",O_RDWR|O_NOCTTY|O_NDELAY);
        if(-1==fd)printf("it can't open the communitation\n");
        else
        {
            i=set_port(fd, 8);
            if(i<0)
            {
                perror("pei zhi cuo wu3\n");
                return 0;
            }
            pthread_mutex_init(&mut,NULL);
            printf("creat preadth\n");
            thread_create();
            printf("Program On..... \n");
            while(1);
            thread_wait();
            close(fd);
        }
            return 0;

}

终端编译命令

$ g++ main.cpp -o thread_test  -lpthread

运行命令

./thread_test

代码解析

先看下全局变量

  • pthread_t thread[2]; 线程池,这里一共需要读写两个线程。
  • pthread_mutex_t mut; 互斥锁,用于保证每个线程执行时不受打扰。
  • int fd; 要打开的串口。

然后看 main 函数

  • 首先打开串口并做错误处理;
  • 串口打开成功后,调用 set_port 函数,设置串口通信属性;
  • 用内核函数 pthread_mutex_init 初始化线程的 mutex ;
  • 自己写的函数 thread_create 创建线程;
  • 然后就是死循环,无尽的等待。

set_port 函数没什么好说的,跟线程没关系,不做解释了。

pthread_mutex_init 的用法也很固定,没有坑。

thread_create 是自己写的函数

  • memset初始化线程池,注意sizeof(thread)返回的是指针的大小,可以分配x个线程,就有x个指针,就需要初始化x*sizeof(thread),这里x=2
  • 创建两个线程,调用内核函数 pthread_create ,注意第1和第3个参数的写法,第一个参数是线程池里分配给该线程的地址,第三个参数是线程函数,原型是void* (* start_routine)(void*),需要注意。
void thread_create(void)
 {
    int temp;
     memset(thread, 0, 2*sizeof(thread));          //comment1
      /*创建线程*/
     if((temp = pthread_create(&thread[0], NULL, thread1, NULL)) != 0)       //comment2
      printf("xian chegn 1 faile\n");
      else
       printf("X1send surcess\n");

       if((temp = pthread_create(&thread[1], NULL, thread2, NULL)) != 0)  //comment3
         printf("2 faile\n");
       else
            printf("X2recend surcess\n");
 }

最重要的是线程函数的函数头

  • 必须写成 void * threadname (void*)
  • 参数列表里的 void* 不能省略,否则会报 类型不能转换 错误
void *thread1(void*)
{
    //something to do
}

编译的时候也有个大坑

$ g++ main.cpp -o thread_test  -lpthread

-lpthread必须要加上,否则会报 函数未定义 错误
原因是,pthread_create函数不在Linux默认的库,编译的时候需要链接其所在的静态库,也就是加上这句话。

其他的一些坑:

  • 乱码出现的原因,是之前上传和接收数据的时候,用了puts函数,打印到屏幕做调试用,但是puts函数的参数只是一个char*,没有长度,那它要打印多少呢?答案就是,打印到出现 ‘\0’为止。
  • 乱码解决方法:往下写数据的时候,在结尾加上’\0’,但是write函数的长度参数不变,’\0’也就不会被写进串口,但是调试的时候输出到屏幕就能及时卡住puts不让它乱码; 往上收数据的时候,本来就要先分配一个buffer嘛,初始化这个buffer,让它全部为’\0’,那无论接收多少数据,有效数据之后的那一位,肯定是’\0’
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值