我在C中有一个多线程程序,只有1个线程函数(thread_read_file),它将从结构中读取文件内容到变量中。 这个函数有一个自动变量thiscontent,其中文件的内容应该使用fread存储。c线程并发和内存混淆
主程序正在执行4个线程以定期读取4个不同的文件将内容更新到内存中。
无论我尝试过什么,我都会在一段时间后得到结果,接着是一些垃圾。 我试着在阅读后强制添加'\ 0',但是不,它会以任何方式显示垃圾。
这里是代码:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#define WAIT_TIME 2
/* change_it:
* 8: picture for texture 0 finished to load into ram, needs to be set to 2 afterwards
* 7: picture for texture 0 loading
* 6: picture for texture 1 finished to load into ram, needs to be set to 2 afterwards
* 5: picture for texture 1 loading
* 4: pre stage 1, initialize time variable for time constant blending
* 3: initial -> allows initial loading of textures
* 2: texture has finished changed, dont change it anymore
* 1: initiate texture change
* 0: don't change any texture */
int change_it = 0;
signed int offset = -1;
int check_id = WAIT_TIME*100+1;
typedef struct {
pthread_mutex_t read_mutex; // synchronize access to reading flag
int reading; // 0 = not reading , 1 = reading , 2 = finished reading
char *content; // content of file
char *file; // file to read
} struct_file_content;
struct_file_content struct_data_file[4];
char *file_content[4];
// temperature in abu dhabi
#define file1 "/home/tias/repository/data/temp_ad.txt"
// temperature in irsch
#define file2 "/home/tias/repository/data/temp_ir.txt"
// change EUR/AED
#define file3 "/home/tias/repository/data/change.txt"
// monitoring data used to color cubes
#define file4 "/home/tias/repository/data/summary.txt"
void change_or_not(signed int* offset, int* check_id, int* change_it) {
if (*offset == -1) {
*offset = (signed int) (time(NULL)) % WAIT_TIME;
}
int delta = (int) ((((long) time(NULL)) - *offset) % WAIT_TIME);
int delta_id = (int) ((long) time(NULL) % (WAIT_TIME * 100));
if (*check_id > WAIT_TIME*100) *check_id = delta_id;
if (delta == 0 && *check_id != delta_id && *change_it == 0) {
//*change_it = 4;
*change_it = 1;
*check_id = delta_id;
}
if (delta == 0 && *check_id != delta_id && *change_it == 2) *change_it = 0;
}
void pretend_texture_blending (int* change_it) {
static old_change_it = 0;
static int ori = 0;
if (old_change_it == 0 && *change_it == 1) {
ori = time(NULL);
}
if (time(NULL) > ori && *change_it == 1) {
ori = time(NULL);
*change_it = 2;
}
old_change_it = *change_it;
}
void *thread_read_file(void *data) {
struct_file_content *thisdata = data;
int mutex_res;
long length;
char *thiscontent = NULL;
// lock mutex
mutex_res = pthread_mutex_lock(&thisdata->read_mutex);
if (mutex_res != 0) {
fprintf(stderr, "thread_read_file() failed to acquire mutex: %s\n", strerror(mutex_res));
pthread_exit(NULL);
} else {
fprintf(stdout, "thread_read_file: mutex locked for file: %s\n",thisdata->file);
}
// end locking procedure
// let's open the file now
FILE *f = fopen(thisdata->file, "r");
// let's get the size of the file and bounce if it is too large
// if size is acceptable, read the file into memory
if (f) {
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek (f, 0, SEEK_SET);
if (length > 39) {
fprintf(stderr, "file %s is too big\n", thisdata->file);
pthread_exit(NULL);
}
thiscontent = (char*)malloc((length+1)*sizeof(char));
if (thiscontent) {
fread(thiscontent, 1, length, f);
} else {
perror("malloc(3) error");
pthread_exit(NULL);
}
fclose(f);
// puzzling result is here :
// first run with the 4 threads always work fine
// next runs will randomly display mixed values/other memory locations
fprintf(stdout,"thiscontent: %s length was %d for file %s\n",thiscontent,length,thisdata->file);
} else {
fprintf(stderr, "cannot open file %s\n", thisdata->file);
pthread_exit(NULL);
}
// file read and fd closed
// free old allocation of this content
free(thisdata->content);
thisdata->reading = 2;
// assign new result to newly freed char*
thisdata->content = thiscontent;
// unlock mutex as everything has been updated
mutex_res = pthread_mutex_unlock(&thisdata->read_mutex);
if (mutex_res != 0) {
fprintf(stderr, "thread_read_file() failed to release mutex: %s\n", strerror(mutex_res));
pthread_exit(NULL);
} else {
fprintf(stdout,"thread_read_file: mutex unlocked for file: %s\n", thisdata->file);
}
// end unlock mutex procedure
return NULL;
}
int main(int argc, char** argv) {
static int init = 1;
int p,q,r,curtime;
float X,Y;
static int data_update_done[4] = { 0,0,0,0 };
static pthread_t thread_file[4];
static int thread_res[4] = { 0,0,0,0 };
static char *files[4];
files[0] = (char*)malloc(sizeof(char)*strlen(file1));
files[1] = (char*)malloc(sizeof(char)*strlen(file2));
files[2] = (char*)malloc(sizeof(char)*strlen(file3));
files[3] = (char*)malloc(sizeof(char)*strlen(file4));
int mutex_err[4];
// init = 1
// => launches the 4 threads for reading the 4 files
//
if (init == 1) {
strcpy(files[0],file1);
strcpy(files[1],file2);
strcpy(files[2],file3);
strcpy(files[3],file4);
for (p = 0 ; p < 4 ; p++) {
mutex_err[p] = pthread_mutex_init(&struct_data_file[p].read_mutex, NULL);
if (mutex_err[p] != 0) {
fprintf(stderr, "pthread_mutex_init(3) error: %s\n", strerror(mutex_err[p]));
exit(EXIT_FAILURE);
}
struct_data_file[p].reading = 1;
struct_data_file[p].content = NULL;
struct_data_file[p].file = files[p];
thread_res[p] = pthread_create(&thread_file[p], NULL, thread_read_file, &struct_data_file[p]);
}
init = 0;
}
// main loop
while (1) {
change_or_not(&offset, &check_id, &change_it);
usleep(50000);
fprintf(stdout,".%u.",change_it);
fflush(stdout);
pretend_texture_blending(&change_it);
for (p = 0 ; p < 4 ; p++) { // updating data if ready, destroying mutex when done, etc...
// lock mutex
mutex_err[p] = pthread_mutex_lock(&struct_data_file[p].read_mutex);
if (mutex_err[p] != 0) {
fprintf(stderr, "pthread_mutex_lock(3) error: %s\n",strerror(mutex_err[p]));
exit(EXIT_FAILURE);
}
// end lock mutex
// data update routine
// is data ready: check variable 'reading' from the struct_data_file struct
// 2 -> yes : update + destroy mutex
// 1 or 0 -> no : unlock mutex
if (struct_data_file[p].reading == 2) { // data is ready
if (file_content[p]) free(file_content[p]);
file_content[p] = (char *)malloc(strlen(struct_data_file[p].content)*sizeof(char));
strcpy(file_content[p],struct_data_file[p].content);
struct_data_file[p].reading = 0;
mutex_err[p] = pthread_mutex_unlock(&struct_data_file[p].read_mutex);
if (mutex_err[p] != 0) {
fprintf(stderr, "Warning: Error destroying mutex: %s\n", strerror(mutex_err[p]));
}
} else {
mutex_err[p] = pthread_mutex_unlock(&struct_data_file[p].read_mutex);
if (mutex_err[p] != 0) {
fprintf(stderr, "pthread_mutex_unlock(3) error: %s\n",strerror(mutex_err[p]));
exit(EXIT_FAILURE);
}
}
// end checking if data is ready
}
if (change_it == 1) {
for (p = 0 ; p < 4 ; p++) {
if (struct_data_file[p].reading == 0) {
if (data_update_done[p] == 0) {
thread_res[p] = pthread_create(&thread_file[p], NULL, thread_read_file, &struct_data_file[p]);
data_update_done[p] = 1;
}
}
}
}
if (change_it == 2) {
for (p = 0 ; p < 4 ; p++) {
data_update_done[p] = 0;
}
}
// end main loop
}
// end main
}
输出
thiscontent: abu dhabi:35.6 length was 14 for file /home/tias/repository/data/temp_ad.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/temp_ad.txt
thread_read_file: mutex locked for file: /home/tias/repository/data/summary.txt
thiscontent: AED/euro:4.09534 length was 16 for file /home/tias/repository/data/change.txt
thiscontent: 11111 length was 5 for file /home/tias/repository/data/summary.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/summary.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/change.txt
.1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..0..1.thread_read_file: mutex locked for file: /home/tias/repository/data/temp_ir.txt
thread_read_file: mutex locked for file: /home/tias/repository/data/temp_ad.txt
thread_read_file: mutex locked for file: /home/tias/repository/data/summary.txt
thread_read_file: mutex locked for file: /home/tias/repository/data/change.txt
thiscontent: AED/euro:4.09534 length was 16 for file /home/tias/repository/data/change.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/change.txt
thiscontent: abu dhabi:35.6 length was 14 for file /home/tias/repository/data/temp_ad.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/temp_ad.txt
thiscontent: irsch:14.6.09534 length was 10 for file /home/tias/repository/data/temp_ir.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/temp_ir.txt
thiscontent: 1111 length was 5 for file /home/tias/repository/data/summary.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/summary.txt
.1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..1..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..2..0..1.thread_read_file: mutex locked for file: /home/tias/repository/data/temp_ad.txt
thread_read_file: mutex locked for file: /home/tias/repository/data/temp_ir.txt
thread_read_file: mutex locked for file: /home/tias/repository/data/summary.txt
thread_read_file: mutex locked for file: /home/tias/repository/data/change.txt
thiscontent: irsch:14.6.09534 length was 10 for file /home/tias/repository/data/temp_ir.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/temp_ir.txt
thiscontent: abu dhabi:35.6 length was 14 for file /home/tias/repository/data/temp_ad.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/temp_ad.txt
thiscontent: AED/euro:4.09534 length was 16 for file /home/tias/repository/data/change.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/change.txt
thiscontent: 1111 length was 5 for file /home/tias/repository/data/summary.txt
thread_read_file: mutex unlocked for file: /home/tias/repository/data/summary.txt
的4个文件具有固定的内容。
前4个结果总是正确的(4个线程读取4个文件,第一组结果总是正确的,据我所见,我已经做了很多测试)。
然而,当显示变量thiscontent(后第一次运行),我得到额外的输出或更少的输出(带有包含11111文件的summary.txt)
例如: 我thiscontent:伊尔施:14.6.09534 我应该得到thiscontent:伊尔施:14.6
而且 我应该得到所有的时间: thiscontent:11111长度为5 但有时我得到 thiscontent:1111长度为5
我不明白为什么,也不能修复它。 我对变量thiscontent是自动的事实感到困惑,因此应该在每次函数调用时都进行初始化。然而,输出显示不同。
它可能是一个内存分配问题,但我目前不知道。
任何帮助非常感谢。 PS:你可能会发现一些无用的代码,这是因为主程序是我编写的一个opengl屏幕保护程序,并且长度为1000行。
我发布的代码是来自此屏幕保护程序的摘录,重现了此问题,但没有大量无用代码用于此非常故障排除。
谢谢
PS NO2:您可以复制/粘贴此代码到一个名为threads.c并使用编译:
gcc -o threads threads.c -lpthread -D_REENTRANT
'的文件[0] =的malloc(1 + strlen的(文件1));'也:' strdup()'是你的朋友。 – wildplasser