Linux多线程
创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
使用前先声明一个进程标识符变量pthread_t *thread;
以及声明固定格式函数void *task(void *arg)
The attr argument points to a pthread_attr_t structure whose
contents are used at thread creation time to determine
attributes for the new thread; this structure is initialized
using pthread_attr_init(3) and related functions.
等待线程
int pthread_join(pthread_t thread, void **retval);
线程退出
void pthread_exit(void *retval);
创建线程时传递参数arg的设计
也可以使用全局变量(不推荐)
由于有共享资源,初始化不方便写在某个线程,所以自定义一个整型数组int fd[10]存放各种描述符
程序框架
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <pthread.h>
int decoding(char *code){
return -1;
}
int netInit(char **argv)
{
int s_fd;
struct sockaddr_in s_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1){
printf("netInit error\n");
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&s_addr.sin_addr);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
listen(s_fd,10);
return s_fd;
}
void *speakControl(void *arg)
{
int fd_Serial = ((int *)arg)[0];
int fd_Relay = ((int *)arg)[1];
while(1){
}
pthread_exit(NULL);
}
void *netControl(void *arg)
{
char code[4] = {0};
int cmd = 0x01;
int fd_Serial = ((int *)arg)[0];
int fd_Relay = ((int *)arg)[1];
int c_fd;
int s_fd = ((int *)arg)[2];
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
socklen_t len = sizeof(struct sockaddr_in);
while(1){
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&len);
if(c_fd == -1){
perror("accept");
continue;
}
if(fork() == 0){
printf("connet success from :%s\n",inet_ntoa(c_addr.sin_addr));
while(1){
}
}
}
pthread_exit(NULL);
}
int main(int argc,char **argv)
{
if(argc != 3){
printf("parameter error\n");
exit(-1);
}
int fd[3] = {0};//0 serial 1 relay 2 c_fd
pthread_t task_Speak;
pthread_t task_Net;
int ret;
fd[0] = serialOpen("/dev/ttyAMA0",9600);
if(fd[0] == -1){
printf("open serial fail\n");
exit(-1);
}
fd[1] = open("/dev/relay",O_RDWR);
if(fd[1] == -1){
printf("open relay fail\n");
perror("open");
exit(-1);
}
fd[2] = netInit(argv);
if(-1==wiringPiSetup())
{
printf("set up error\n");
exit(-1);
}
ret = pthread_create(&task_Speak,NULL,speakControl,(void *)fd);
if(ret != 0){
printf("create task1 fail\n");
exit(-1);
}
ret = pthread_create(&task_Net,NULL,netControl,(void *)fd);
if(ret != 0){
printf("create task2 fail\n");
perror("pthread_create");
exit(-1);
}
pthread_join(task_Speak,NULL);
pthread_join(task_Net,NULL);
return 0;
}
程序测试
由于前面的测试,大大降低这次程序的测试难度,直接接上语音模块测试语音控制线程,运行客户端程序测试网络控制线程
现阶段总结
一丶使用了临界资源,却没有考虑资源竞争问题,应加上互斥锁
二丶main函数初始化可以考虑封装在一个函数,便于以后的拓展提升
三丶考虑改变ascll码指令的格式,之前使用“OA”,"OR"等英文单词缩写,目的是配合语音模块,考虑改成一些比较通用的无意义指令,如“41”,“42”。这样以后进行不同操作时,不需要修改decoding函数,只需合理分配指令,修改线程里面的操作。语音识别模块也只需要修改识别的内容,不需要修改发送的指令格式。
decoding函数
int decoding(char *code)
{
if(strstr(code,"OA") != NULL) return 0x00;
if(strstr(code,"OR") != NULL) return 0x10;
if(strstr(code,"OG") != NULL) return 0x20;
if(strstr(code,"OY") != NULL) return 0X30;
if(strstr(code,"CA") != NULL) return 0x01;
if(strstr(code,"CR") != NULL) return 0x11;
if(strstr(code,"CG") != NULL) return 0x21;
if(strstr(code,"CY") != NULL) return 0x31;
if(strstr(code,"GD") != NULL) return 0x0f;
if(strstr(code,"EX") != NULL) return 0xff;
return -1;
}