我在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