[编辑]我添加了所有主要代码和此代码使用的一些外部函数。代码很长,但总的来说,它向设备发送信息,测量容器中水的某些参数,设备响应传感器测量的相应值。 之后,代码使用此值来修改水的水平和温度。打印容器的当前状态并生成log.txt文件。[/ Edit]
我想在C中做一个类似构造函数的面向对象的函数,但是我的malloc()之后我的结构及其成员的地址没有改变。我看到了这个答案Changing address contained by pointer using function,我知道我的问题是什么,但仍然无法解决。 下面是我执行构造函数的代码:
udp.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "udp.h"
#define BUF_SIZE 1000
#define HEADER_SIZE
typedef struct{
int socket;
char header[4];
float *send_value;
char *message_buffer;
}message;
void build_message(message **msg, int socket, char header[], float *send_value){
*msg = (message *)malloc(sizeof(message));
(*msg)->socket = socket;
strncpy((*msg)->header, header, 4);
(*msg)->send_value = send_value;
(*msg)->message_buffer = NULL;
(*msg)->message_buffer = malloc(BUF_SIZE);
//(**msg).message_buffer = (char *)(msg+sizeof(int) + sizeof(float *) + sizeof(char *)*3);
}
int prepara_socket_cliente(char *host, char *porta)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int sfd, s;
/* Obtain address(es) matching host/port */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4/ or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
s = getaddrinfo(host, porta, &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully connect(2).
If socket(2) (or connect(2)) fails, we (close the socket
and) try the next address. */
for( rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue;
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break; /* Success */
close(sfd);
}
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not connect\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(result); /* No longer needed */
return sfd;
}
float receive_message(message *msg){
ssize_t nread;
int len;
//sprintf(msg->message_buffer, "%s0.0", msg->header);
len = strlen(msg->message_buffer)+1;
int rc;
if (len + 1 > BUF_SIZE){
fprintf(stderr, "Ignoring long message in argument\n");
exit(EXIT_FAILURE);
}
if((rc = write(msg->socket, msg->message_buffer, len)) != len){
printf("%d, %d\n", len, rc);
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(msg->socket, msg->message_buffer, BUF_SIZE);
if (nread == -1){
perror("read");
exit(EXIT_FAILURE);
}
return atof(msg->message_buffer+3);
}
int send_message(message *msg){
ssize_t nread;
int len;
//sprintf(msg->message_buffer, "%s%.1f", msg->header, *msg->send_value);
len = strlen(msg->message_buffer)+1;
int rc;
if (len + 1 > BUF_SIZE){
fprintf(stderr, "Ignoring long message in argument\n");
exit(EXIT_FAILURE);
}
if((rc = write(msg->socket, msg->message_buffer, len)) != len){
printf("%d, %d\n", len, rc);
fprintf(stderr, "partial/failed write\n");
exit(EXIT_FAILURE);
}
nread = read(msg->socket, msg->message_buffer, BUF_SIZE);
if (nread == -1){
perror("read");
exit(EXIT_FAILURE);
}
return 0;
}
的main.c
#include<pthread.h>
#include<stdio.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<unistd.h>
#include<math.h>
#include<time.h>
#include<termios.h>
#include"controller.h"
#include"screen.h"
#include"myIO.h"
#include"my_time.h"
#include"data_structures.h"
#include"udp.h"
#define NUM_THREADS 5
#define MAX_PARAM_SIZE 20
#define MAX_BUFFER_SIZE 1200
//variables
typedef enum {IDLE, QUIT, CHANGE_LEVEL_REF, CHANGE_TEMP_REF} command_type;
struct timespec t1;
struct timespec t2;
pthread_cond_t screen = PTHREAD_COND_INITIALIZER;
pthread_cond_t cmd = PTHREAD_COND_INITIALIZER;
pthread_cond_t barrier = PTHREAD_COND_INITIALIZER;
int count[2] = {0,0};
command_type command = IDLE;
double_buffer* log_buffer;
char* port = NULL;
char* host = NULL;;
int socket_cliente;
real Ta, Ti, No;
real T=0;
real H=0;
real Q=0;
real Nf=0;
real Ni=0;
real Na=0;
real href = 2.0;
real tref = 25.0;
pthread_mutex_t em_scan;
pthread_mutex_t em;
void init(){
port = (char *)malloc(sizeof(char)*MAX_PARAM_SIZE);
host = (char *)malloc(sizeof(char)*MAX_PARAM_SIZE);
log_buffer = build_double_buffer();
}
//threads
void *LevelControl(void *threadid){
/**********************************************************
*thread responsible for controling the water level
*********************************************************/
controller* levelControl = NULL;
levelControl = build_controller();
levelControl->kp = 10000.0;
levelControl->ki = 0.0;
levelControl->kd = 0.0;
levelControl->error_thresh = 1.0;
levelControl->step_time = 0.7;
levelControl->max_actuator_value = 100.0;
levelControl->min_actuator_value = 0.0;
int intervalo = 90000000;
message *message_H = NULL;
build_message(&message_H, socket_cliente, "sh-", &H);
sprintf(message_H->message_buffer, "%s0.0", message_H->header);
message *message_Nf = NULL;
build_message(&message_Nf, socket_cliente, "anf", &Nf);
message *message_Ni = NULL;
build_message(&message_Ni, socket_cliente, "ani", &Ni);
loop_1:
if(command != QUIT){
pthread_mutex_lock(&em);
H = receive_message(message_H);
levelControl->error = href - H;
if(levelControl->error < 0.0){
levelControl->error = -levelControl->error;
Nf = PID_Update(levelControl);
Ni = 0.0;
}else{
Ni = PID_Update(levelControl);
Nf = 0.0;
}
sprintf(message_Nf->message_buffer, "%s%f", message_Nf->header, *message_Nf->send_value);
send_message(message_Nf);
sprintf(message_Ni->message_buffer, "%s%f", message_Ni->header, *message_Ni->send_value);
send_message(message_Ni);
count[1] = 1;
if((count[0] == 1) & (count[1] == 1)) pthread_cond_signal(&barrier);
next_timer(t1, intervalo);
pthread_mutex_unlock(&em);
goto loop_1;
}else return NULL;
}
void *TempControl(void *threadid){
/**********************************************************
* thread responsible for controling the temperature
*********************************************************/
controller *tempControl = NULL;
tempControl = build_controller();
tempControl->kp = 10000.0;
tempControl->ki = 0.0;
tempControl->kd = 0.0;
tempControl->error_thresh = 20.0;
tempControl->step_time = 0.7;
tempControl->max_actuator_value = 10000.0;
tempControl->min_actuator_value = 0.0;
int intervalo = 70000000;
message *message_T = NULL;
build_message(&message_T, socket_cliente, "st-", &T);
sprintf(message_T->message_buffer, "%s0.0", message_T->header);
message *message_Q = NULL;
build_message(&message_Q, socket_cliente, "aq-", &Q);
message *message_Na = NULL;
build_message(&message_Na, socket_cliente, "ana", &Na);
char *log_string = NULL;
log_string = (char *)malloc(sizeof(char)*MAX_BUFFER_SIZE);
// while(command != QUIT){
loop_2:
if(command != QUIT){
pthread_mutex_lock(&em);
T = receive_message(message_T);
tempControl->error = tref - T;
Q = PID_Update(tempControl);
sprintf(message_Q->message_buffer, "%s%f", message_Q->header, *message_Q->send_value);
send_message(message_Q);
if(Q == tempControl->max_actuator_value){
Na = 10.0;
}else if(Q == tempControl->min_actuator_value){
Na = 0.0;
}
sprintf(message_Na->message_buffer, "%s%f", message_Na->header, *message_Na->send_value);
send_message(message_Na);
count[0] = 1;
if((count[0] == 1) & (count[1] == 1)) pthread_cond_signal(&barrier);
pthread_mutex_unlock(&em);
sprintf(log_string, "Temperura: %f\n", T);
setDoubleBuffer(log_buffer, log_string);
next_timer(t2, intervalo);
goto loop_2;
}else return NULL;
// pthread_exit(NULL);
}
void *Status(void *threadid){
/**********************************************************
*thread responsible for printing the current status on
*the screen and setting tref and href
*********************************************************/
message *message_Ta = NULL;
build_message(&message_Ta, socket_cliente, "sta", &Ta);
sprintf(message_Ta->message_buffer, "%s0.0", message_Ta->header);
message *message_Ti = NULL;
build_message(&message_Ti, socket_cliente, "sti", &Ti);
sprintf(message_Ti->message_buffer, "%s0.0", message_Ti->header);
message *message_No = NULL;
build_message(&message_No, socket_cliente, "sno", &No);
sprintf(message_No->message_buffer, "%s0.0", message_No->header);
pthread_mutex_lock(&em);
while((count[0] != 1) | (count[1] != 1)) pthread_cond_wait(&barrier, &em);
pthread_mutex_unlock(&em);
//while(command != QUIT){
loop_3:
switch(command){
case IDLE:
pthread_mutex_lock(&em);
clearScreen();
Ta = receive_message(message_Ta);
Ti = receive_message(message_Ti);
No = receive_message(message_No);
printf("/********************************************************************************************************\n");
printf("*STATUS\n");
printf("*reference temperature: %f\n", tref);
printf("*reference water level: %f\n", href);
printf("*current temperature: %f\n", T);
printf("*current water level: %f\n", H);
printf("*other sensor value => Ni = %f, No = %f, Na = %f, Nf = %f, Ta = %f, Ti = %f\n", Ni, No, Na, Nf, Ta,Ti);
printf("*\n");
printf("*\n");
printf("*\n");
printf("*(q)uit, change (l)evel reference, change (t)emperature reference\n");
pthread_mutex_unlock(&em);
sleep(1);
break;
case CHANGE_LEVEL_REF:
pthread_mutex_lock(&em_scan);
printf("insert new Level reference\n");
scanf("%f", &href);
pthread_cond_signal(&screen);
while(command != IDLE){
pthread_cond_wait(&cmd, &em_scan);
}
pthread_mutex_unlock(&em_scan);
break;
case CHANGE_TEMP_REF:
pthread_mutex_lock(&em_scan);
printf("insert new Temperature reference\n");
scanf("%f", &tref);
pthread_cond_signal(&screen);
while(command != IDLE){
pthread_cond_wait(&cmd, &em_scan);
}
pthread_mutex_unlock(&em_scan);
case QUIT:
fprintf(stderr, "get saiu\n");
return NULL;
}
goto loop_3;
//return NULL;
}
void *GetReferences(void *threadid){
/**********************************************************
*thread responsible for changing the program mode
*********************************************************/
char temp;
//while(command != QUIT){
loop_4:
temp = getch();
switch(temp){
case 'q':
command = QUIT;
printf("%c\n --------------------------------------------------------\n", temp);
return NULL;
case 'l':
pthread_mutex_lock(&em_scan);
command = CHANGE_LEVEL_REF;
pthread_cond_wait(&screen, &em_scan);
command = IDLE;
pthread_cond_signal(&cmd);
pthread_mutex_unlock(&em_scan);
break;
case 't':
pthread_mutex_lock(&em_scan);
command = CHANGE_TEMP_REF;
pthread_cond_wait(&screen, &em_scan);
command = IDLE;
pthread_cond_signal(&cmd);
pthread_mutex_unlock(&em_scan);
}
goto loop_4;
}
void *Log(void *threadid){
char *receive_buffer = NULL;
receive_buffer = (char *)malloc(sizeof(char)*MAX_BUFFER_SIZE);
//while(command != QUIT){
loop_5:
if(command != QUIT){
get_buffer(receive_buffer, log_buffer);
write_log(receive_buffer);
goto loop_5;
}else return NULL;
}
int main (int argc, char *argv[]){
init();
pthread_mutex_init(&em_scan, NULL);
pthread_mutex_init(&em, NULL);
init_nano_timer(t1);
init_nano_timer(t2);
clearScreen();
printf("Enter the port where to be used in the udp communication\n");
scanf("%s", port);
strcpy(host, "localhost");
socket_cliente = prepara_socket_cliente(host, port);
pthread_t threads[NUM_THREADS];
int rc;
int t;
void *threadName[NUM_THREADS];
threadName[0] = TempControl;
threadName[1] = LevelControl;
threadName[2] = Status;
threadName[3] = GetReferences;
threadName[4] = Log;
for(t=0; t<NUM_THREADS; t++){
rc = pthread_create(&threads[t], NULL, threadName[t], (void *)t);
if(rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(1);
}
}
for(t=0; t<NUM_THREADS; t++){
rc = pthread_join(threads[t], NULL);
if(rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(1);
}
}
return 0;
}
顺便说一下,我在这些代码中使用了线程,即使没有互斥锁,这段代码也是线程安全的吗?
答案 0 :(得分:2)
正如@Sourav Ghosh正确地评论你:
void build_message(message **msg, int socket, char header[], float *send_value)
{
*msg = malloc(sizeof(message));
(*msg)->socket = socket;
strncpy((*msg)->header, header, 4);
(*msg)->send_value = send_value;
(*msg)->message_buffer = malloc(BUF_SIZE);
}
将结构更改为:
typedef struct{
int socket;
char header[4];
float *send_value;
char *message_buffer;
}message;