ARM技术论坛
直播中

张杰

7年用户 1258经验值
私信 关注
[经验]

怎样去解决在imx6q的ARM Cortex-A9处理器上执行c++报错的问题

1. 说明
硬件环境:
迅为imx6q开发板, ARM Cortex-A9的处理器
7.0寸电容触摸屏
软件环境:
使用的是迅为官方提供的u-boot.imx , uImage, Qt5.7的rootfs根文件系统。
交叉编译工具链:arm-linux-gcc-4.8.3
问题:
在使用迅为提供的Qt5.7的系统时,发现板子的动态库不支持c++ 的东西,只支持Qt,于是就开始了找原因的过程。
下面是在迅为提供的Qt5.7的系统上执行c++的报错问题:
1.jpg
找不到动态库 GLIBCXX_3.4.11
通过执行 strings /lib/libstdc++.so.6 |grep GLIBCXX  后:
1.jpg
发现确实找不到 GLIBCXX_3.4.11。
解决方法:
从网上下载比较新的 libstdc++.so.6.0.17 库,
然后执行如下步骤:
将 libstdc++.so.6.0.17拷贝到开发板 /lib/ 目录下
删除原来的libstdc++.so.6, 执行 rm -rf libstdc++.so.6
建立新的指向libstdc++.so.6.0.17的软链接, 即:
ln -s libstdc++.so.6.0.17 libstdc++.so.6
至此,板子的环境问题就全部解决
2. 板子测试一个c++11的多线程的Demo
#include
#include
#include
#include
#include
//#include
#include
void led_proc1();
void led_proc2();
#define MAX 100
int main(void)
{
std::thread t1(led_proc1);
std::thread t2(led_proc2);
t1.join();
t2.join();
//std::cout << "thread john finish" << std::endl;
printf("thread john finish");
return 0;
}
void led_proc1()
{
    int fd,LedOnOfftimes;
char gpio[MAX],cmd[MAX];
char *leds = "/dev/leds_ctl";
LedOnOffTimes = MAX;
printf("leds light on and off 5 times rn");
if((fd = open(leds, O_RDWR|O_NOCTTY|O_NDELAY))<0)
printf("open %s failedn",leds);   
else
{
    printf("open %s successrn",leds);
while(LedOnOffTimes--)
{
printf("ioctl leds %d timesn",LedOnOffTimes);
ioctl(fd,0,0); //parameter 2 is cmd ,cmd = 1 leds on
//ioctl(fd,0,1);
sleep(1);
ioctl(fd,1,0);
//ioctl(fd,1,1);
sleep(1);
}
    }
close(fd);
}
void led_proc2()
{
int temp = 100;
while(1)
{
//std::cout << "temp= " << temp-- << std::endl;
printf("temp= %drn",temp--);
sleep(2);
}
}
交叉编译命令如下:(注意,编译c++的编译器版本务必在4.8以上才支持)
arm-none-linux-gnueabi-g++ -lpthread led_cpp_thread.cpp -o ledThread3 -std=c++11
编译注意事项:
因为用到了多线程,编译时要加上 -lpthread 命令
因为用到c++11, 编译时要用到  -std=c++11 命令
3. 板子上测试posix标准的多线程代码
从《Unix环境高级编程》的第11章 线程 章节里,可以知道如何使用posix接口创建一个多线程。
3.1 创建线程:
包含头文件: #include
int pthread_create(pthread_t *thread, const pthread_attr_t  *attr, void *(*start_rtn)  (void*),void  *arg);
*thread:     线程id (指向线程标识符的指针)
*attr:          线程属性(通常为空)
*start_rtn: 线程要执行的函数(线程运行函数的起始地址)
*arg:          start_rtn的参数
注意事项:
返回值为0才算成功,其它表示错误
编译时需要加上 -lpthread库
线程函数都是 void* 的返回类型
示例如下:
pthread_t tid_1; //存放线程ID
int err = pthread_create(&tid_1, NULL, led_proc_1, NULL);
if(err !=0){
printf("can't create thread led_proc1");
}
pthread_join(tid_1, NULL); //线程阻塞,防止main的进程退出
3.2 测试示例Demo
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void* led_proc1(void *args);
void* led_proc2(void *args);
#define MAX 100
pthread_t ntid1,ntid2;
void print_tids(const char* s)
{
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %u tid  %u (0x%x)n", s, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
}
int main(void)
{
int err = pthread_create(&ntid1, NULL, led_proc1, NULL);
if(err !=0)
{
//err_quit("can't create thread %sn", strerror(err));
printf("can't create thread led_proc1");
}
    err = pthread_create(&ntid2, NULL, led_proc2, NULL);
if(err !=0)
{
//err_quit("can't create thread %sn", strerror(err));
printf("can't create thread led_proc2");
}
print_tids("main thread: ");
pthread_join(ntid1, NULL);
pthread_join(ntid2, NULL);
printf("exiting...");
sleep(2);
exit(0);
}
void* led_proc1(void *args)
{
    int fd,LedOnOffTimes;
char *leds = "/dev/leds_ctl";
LedOnOffTimes = MAX;
printf("leds light on and off 5 times rn");
if((fd = open(leds, O_RDWR|O_NOCTTY|O_NDELAY))<0)
{
printf("open %s failedn",leds);
}
else
{
    printf("open %s successrn",leds);
while(LedOnOffTimes--)
{
ioctl(fd,0,0); //parameter 2 is cmd ,cmd = 1 leds on
//ioctl(fd,0,1);
sleep(1);
ioctl(fd,1,0);
//ioctl(fd,1,1);
sleep(1);
}
    }
close(fd);
}
void* led_proc2(void *args)
{
int temp = 1000;
while(1)
{
printf("temp= %drn",temp--);
sleep(2);
}
}
4. 创建进程以及进程间通讯
4.1 fork创建父子进程
从《Unix环境高级编程》里fork介绍如下:
1.jpg
下面是一个使用fork() 函数创建进程的示例:
#include
#include
#include
void father_process();
void son_process();
void main()
{
    pid_t pid;
    pid = fork();
   if(pid>0) //pid>0的是父进程
   {
      printf("this is father processn");
      father_process();
   }
   else if(pid==0) //pid=0的是子进程
   {
      printf("this is son processn");
      son_process();
   }
}
void father_process()  //父进程
{
      int count = 0;
      for (;;)
      {
         printf("father: %dn", count++);
         sleep(1);
      }
}
void son_process()  //子进程
{
      int count = 0;
      for (;;)
      {
         printf("son: %dn", count++);
         sleep(1);
      }
}
        看这个程序的时候,头脑中必须首先了解一个概念:在语句pid = fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的代码部分完全相同,将要执行的下一条语句都是if(pid>0) ……。
        这2个进程中,原先就存在的那个被称作“父进程”,新出现的那个被称作“子进程”。父子进程的区别除了进程标志符(process ID)不同外,变量pid的值也不相同,pid存放的是fork的返回值。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
在父进程中,fork返回新创建子进程的进程ID,进程ID>0;
在子进程中,fork返回0;
如果出现错误,fork返回一个负值;
4.2 进程间通讯之管道
管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。
     其特征如下:
1. 其本质是一个伪文件(实为内核缓冲区)
2. 由两个文件描述符引用,一个表示读端,一个表示写端。
3. 规定数据从管道的写端流入管道,从读端流出。
    管道的局限性:
① 数据自己读不能自己写。
② 数据一旦被读走,便不在管道中存在,不可反复读取。
③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
④ 只能在有公共祖先的进程间使用管道。
创建管道:
1.jpg
简单示例如下:
#include
int fd[2];  //fd[0] 是输入端  fd[1] 是输出端
if(pipe(fd)== -1)
{
    perror("pipe err");
}
下面是一段父子进程间使用管道进行数据读写的Demo
#include
#include
#include
#include
#include
void sys_error(const char *str)
{
   perror(str);
   exit(1);
}
void main()
{
   char buf[100];
   char *p = "test for pipen";
   int fd[2]; //fd[0] 是标准输入  fd[1] 是标准输出
   if(pipe(fd)==-1) //创建管道
   {
      sys_error("pipe");
   }
   pid_t pid = fork();
   if(pid > 0)
   {
      printf("this is father processn");
      close(fd[1]);           //读之前先关闭fd[1],防止子进程没法打开这个fd[1]
      int len = read(fd[0], buf, sizeof(buf)); //阻塞型I/O
      write(STDOUT_FILENO, buf, len);  //STDOUT_FILENO  表示标准输出描述符
      close(fd[0]);
      //father_process();
   }
   else if(pid == 0)
   {
      printf("this is son processn");
      close(fd[0]);
      write(fd[1], p, strlen(p));
      close(fd[1]);
      //son_process();
   }
   else
   {
      sys_error("fork err");
   }
}
进程通讯之套接字
当无血缘关系的进程间通讯时,就需要用到socket 了。
1.jpg
server.c 代码如下:
/*
    Faker @2020-12-10
*/
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, const char* argv[])
{
    int lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if(lfd == -1)
    {
        perror("socket error");
        exit(1);
    }
    unlink("server.sock");
    //bind
    struct sockaddr_un serv;
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");
    int ret = bind(lfd, (struct sockaddr*)&serv, sizeof(serv));
    if(ret == -1)
    {
        perror("bind err");
    }
    //Listen
    ret = listen(lfd, 36);
    if(ret == -1)
    {
        perror("listen error");
        exit(1);
    }
    //wait connect request
    struct sockaddr_un client;
    socklen_t len = sizeof(client);
    int cfd = accept(lfd, (struct sockaddr*)&client, &len);
    if(cfd == -1)
    {
        perror("accept error");
        exit(1);
    }
    printf("client bind file: %sn", client.sun_path);
    //Comm
    while(1)
    {
        char buf[1024] = {0};
        int recvlen = recv(cfd, buf, sizeof(buf),0);
        if(recvlen == -1)
        {
            perror("recv error");
            exit(1);
        }
        else if(recvlen == 0)
        {
            printf("clent disconnect .....n");
            close(cfd);
            break;
        }
        else
        {
            printf("recv buf: %sn", buf);
            send(cfd, buf, recvlen, 0);
        }
    }
    close(cfd);
    close(lfd);
    return 0;
}
client.c 代码如下:
/*
    Faker @2020-12-10
    client.c
*/
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, const char* argv[])
{
    int fd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if(fd == -1)
    {
        perror("socket error");
        exit(1);
    }
    ulink("client.sock");
    //bind a socket file for client
    struct sockaddr_un client;
    client.sun_family = AF_LOCAL;
    strcpy(client.sun_path, "client.sock");
    int ret = bind(fd, (struct sockaddr*)&client, sizeof(client));
    if(ret == -1)
    {
        perror("bind err");
        exit(1);
    }
    //initial server info
    struct sockaddr_un serv;
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");
    //connect server
    connect(fd, (struct sockaddr*)&serv, sizeof(serv));
    //Comm
    while(1)
    {
        char buf[1024] = {0};
        fgets(buf, sizeof(buf), stdin);
        send(fd, buf,strlen(buf)+1, 0 );
        //recv data
        recv(fd, buf, sizeof(buf), 0);
        printf("recv buf: %sn", buf);
    }
    close(fd);
    return 0;
}
如果提示 bind err: Address already in use  解决方法:
       在代码中使用 ulink("client.sock"); 和 ulink("server.sock"); 删除掉这2文件即可。

原作者:少年丶趁年轻

更多回帖

发帖
×
20
完善资料,
赚取积分