当线程数增加时,多线程文件IO程序表现不可预测

时间:2018-03-13 04:38:53

标签: c++ multithreading file-io pthreads mutex

尝试通过写入各种块大小和不同数量的线程来创建1Mb(1048576Byte)文件。当int NUM_THREADS = 1#include <pthread.h> #include <string> #include <iostream> #define TenGBtoByte 1048576 #define fileToWrite "/tmp/schatterjee.txt" using namespace std; pthread_mutex_t mutexsum; struct workDetails { int threadcount; int chunkSize; char *data; }; void *SPWork(void *threadarg) { struct workDetails *thisWork; thisWork = (struct workDetails *) threadarg; int threadcount = thisWork->threadcount; int chunkSize = thisWork->chunkSize; char *data = thisWork->data; long noOfWrites = (TenGBtoByte / (threadcount * chunkSize)); FILE *f = fopen(fileToWrite, "a+"); for (long i = 0; i < noOfWrites; ++i) { pthread_mutex_lock(&mutexsum); fprintf(f, "%s", data); fflush (f); pthread_mutex_unlock(&mutexsum); } fclose(f); pthread_exit((void *) NULL); } int main(int argc, char *argv[]) { int blocksize[] = {1024}; int NUM_THREADS = 2; for (int BLOCKSIZE: blocksize) { char *data = new char[BLOCKSIZE]; fill_n(data, BLOCKSIZE, 'x'); pthread_t thread[NUM_THREADS]; workDetails detail[NUM_THREADS]; pthread_attr_t attr; int rc; long threadNo; void *status; /* Initialize and set thread detached attribute */ pthread_mutex_init(&mutexsum, NULL); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (threadNo = 0; threadNo < NUM_THREADS; threadNo++) { detail[threadNo].threadcount = NUM_THREADS; detail[threadNo].chunkSize = BLOCKSIZE; detail[threadNo].data = data; rc = pthread_create(&thread[threadNo], &attr, SPWork, (void *) &detail[threadNo]); if (rc) exit(-1); } pthread_attr_destroy(&attr); for (threadNo = 0; threadNo < NUM_THREADS; threadNo++) { rc = pthread_join(thread[threadNo], &status); if (rc) exit(-1); } pthread_mutex_destroy(&mutexsum); delete[] data; } pthread_exit(NULL); } 时,创建的文件大小与给定的相同,即10MB。

然而,当我将线程数增加到4时,创建的文件大小约为400MB;为什么会出现这种异常?

long noOfWrites = (TenGBtoByte / (threadcount * chunkSize));

N.B。 - 1)它是一个基准测试任务,所以按照他们的要求进行。 2){{1}}基本上计算每个线程应写入多少次以获得10MB的组合大小。 4)我试图将Mutex锁定在不同的位置。所有结果都是相同的结果

也欢迎有关该计划其他变更的建议

2 个答案:

答案 0 :(得分:2)

您正在分配和初始化数据数组,如下所示:

char *data = new char[BLOCKSIZE];
fill_n(data, BLOCKSIZE, 'x');

然后您使用fprintf将文件写入文件:

fprintf(f, "%s", data);

函数fprintf期望data是以空字符结尾的字符串。这已经是一种未定义的行为。如果这适用于少量线程,那是因为内存块之后的内存恰好包含零字节。

除此之外,程序中的互斥锁没有用处,可以删除。文件锁定也是多余的,因此您可以使用fwrite_unlockedfflush_unlocked来编写数据,因为每个线程都使用单独的FILE对象。基本上,程序中的所有同步都在内核中执行,而不是在用户空间中执行。

即使在删除互斥锁并使用_unlocked函数后,无论线程数如何,程序都可以可靠地创建1 MB文件。因此,无效的文件写入似乎是您唯一的问题。

答案 1 :(得分:0)

@Ivan是的!是!是!你绝对是我的朋友。除了一个小事实。互斥是必要的。这是最终的代码。尝试删除互斥锁,文件大小会有所不同。

#include <pthread.h>
#include <string>
#include <iostream>
#define TenGBtoByte 1048576
#define fileToWrite "/tmp/schatterjee.txt"

using namespace std;
pthread_mutex_t mutexsum;;
struct workDetails {
    int threadcount;
    int chunkSize;
    char *data;
};

void *SPWork(void *threadarg) {

    struct workDetails *thisWork;
    thisWork = (struct workDetails *) threadarg;
    int threadcount = thisWork->threadcount;
    int chunkSize = thisWork->chunkSize;
    char *data = thisWork->data;
    long noOfWrites = (TenGBtoByte / (threadcount * chunkSize));
    FILE *f = fopen(fileToWrite, "a+");

    for (long i = 0; i < noOfWrites; ++i) {
        pthread_mutex_lock(&mutexsum);
        fprintf(f, "%s", data);
        fflush (f);
        pthread_mutex_unlock(&mutexsum);
    }
    fclose(f);
    pthread_exit((void *) NULL);
}

int main(int argc, char *argv[]) {
    int blocksize[] = {1024};
    int NUM_THREADS = 128;
    for (int BLOCKSIZE: blocksize) {
        char *data = new char[BLOCKSIZE+1];
        fill_n(data, BLOCKSIZE, 'x');
        data[BLOCKSIZE] = NULL;

        pthread_t thread[NUM_THREADS];
        workDetails detail[NUM_THREADS];
        pthread_attr_t attr;
        int rc;
        long threadNo;
        void *status;
        pthread_mutex_init(&mutexsum, NULL);
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
        for (threadNo = 0; threadNo < NUM_THREADS; threadNo++) {
            detail[threadNo].threadcount = NUM_THREADS;
            detail[threadNo].chunkSize = BLOCKSIZE;
            detail[threadNo].data = data;
            rc = pthread_create(&thread[threadNo], &attr, SPWork, (void *) &detail[threadNo]);
            if (rc) exit(-1);
        }
        pthread_attr_destroy(&attr);
        for (threadNo = 0; threadNo < NUM_THREADS; threadNo++) {
            rc = pthread_join(thread[threadNo], &status);
            if (rc) exit(-1);
        }
        pthread_mutex_destroy(&mutexsum);
        delete[] data;
    }
    pthread_exit(NULL);
}