首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >无法在C++中使用线程创建文件

无法在C++中使用线程创建文件
EN

Stack Overflow用户
提问于 2013-08-06 05:55:27
回答 2查看 333关注 0票数 0

我编写了一个程序,使用pthread创建了许多文件。例如,如果我传递“./ioload110”,这个程序应该创建总共占用1MB磁盘空间的10个文件(即output0、output1、...、output9)。但是,当我运行该程序时,它无法在执行后创建所有10个文件。我想知道是什么导致了这个问题?

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

int numOfThreads;
int sizeOfDisk;
int blockSize = 4096;


void *write(void *name)
{
     FILE * fd;
     char fname[100];
     strcpy(fname,"output");
     strcat(fname, (char *)name);
     int fileSize = sizeOfDisk * 1024 * 1024 / blockSize / numOfThreads; 
     char block[fileSize];
     memset(block, 0, sizeof(*block));

     int i;
     fd = fopen(fname, "w");

     if (NULL == fd)
     {
        fprintf(stderr, "ERROR: FAILED TO OPEN FILE %s\n", fname);
        return NULL;
     }

     for (i = 0; i < fileSize; i++)
        fwrite(block, sizeof(blockSize), 4096, fd);

     fclose(fd);
}

int main(int argc, char * argv[])
{
    if (argc != 3)
    {
        printf("Usage: %s sizeOfDiskInMB #OfThreads\n", argv[0]);
        exit(1);
    }

    sizeOfDisk = atoi(argv[1]);
    numOfThreads = atoi(argv[2]);

    pthread_t ths[numOfThreads];
    int i;

    for (i = 0; i < numOfThreads; i++)
    {
        char ibuffer [100];
        snprintf(ibuffer, sizeof(ibuffer), "%d", i);

        if (pthread_create(&ths[i], NULL, write, (void *)&ibuffer)) 
        {
            fprintf(stderr, "ERROR: FAILD TO CREATE THREAD %d", i);
            exit(1);
        }
    }

    for (i = 0; i < numOfThreads; i++)
    {
        pthread_join(ths[i], 0);
    }

}
EN

回答 2

Stack Overflow用户

发布于 2013-08-06 05:58:09

每个线程都会被传递一个指向ibuffer的指针。对于主线程循环的每次迭代,ibuffer很可能都有相同的地址,这意味着所有线程都试图从同一内存中读取数据。

不能保证每个新线程都会被调度,并且会在主线程开始其循环的下一次迭代之前创建文件,从而更新ibuffer的内容。这可能会导致多个线程尝试创建相同的文件,或者一些线程在稍后的snprintf调用过程中尝试读取它们的文件名。

要解决此问题,您需要让每个线程发出已完成构造的信号,或者在主线程中存储一个文件名数组,将一个指向不同实例的指针传递到每个线程中。

代码语言:javascript
复制
void *write(void *name)
{
    FILE * fd;
    char fname[100];
    snprintf(fname, sizeof(fname), "output%d", *(int*)name);
    ...


int main(int argc, char * argv[])
{
    ....
    pthread_t ths[numOfThreads];
    int fileNum[numOfThreads];
    int i;
    for (i = 0; i < numOfThreads; i++)
    {
        fileNum[i] = i;
        if (pthread_create(&ths[i], NULL, write, (void *)&fileNum[i])) 
        {
            fprintf(stderr, "ERROR: FAILD TO CREATE THREAD %d", i);
            exit(1);
        }
    }
    ....
票数 3
EN

Stack Overflow用户

发布于 2013-08-06 07:34:37

感谢您的提问,我已经在C#中开发了线程,所以这是一篇关于实现C/WIN32线程的很好的评论。

首先要注意的是,这段代码是使用Microsoft C编译器为Windows机器编写的。对于*nix系统,您需要执行类似的操作,但调用和宏名称不同。然而,一般原则是相同的。

  1. 为每个线程创建一个唯一的存储区域。放置线程特定信息。进入这片区域。
  2. 初始化一个线程,传递给它这个区域,以及它的堆栈的大小(在MS中,0 size给线程与进程相同的堆栈大小。
  3. main()中初始化所有线程后,等待它们完成。使用信号量测试完成。

对于Windows,您需要使用线程安全库,但它看起来像XP或更高版本的任何系统都提供线程安全的DLL,如msvcrt.lib。此外,还有一个_begintheadex版本,它有更多的功能,并被推荐。

最后,这段代码还不能在实际的应用程序中使用。它还需要做很多事情(比如使用_beginthreadex),但为了讨论的目的,这是一个很好的开始。

代码语言:javascript
复制
// Compiled on Eclipse/Microsoft C Compiler
// compile with: /MT /D "_X86_" /c
// processor: x86
#include <Windows.h>
#include <process.h>    /* _beginthread, _endthread */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

struct ThreadParameterBlock
{
    int  threadNr;     //
    char fname[13];    // outputxx.bin\0
    int  numBlocks;    // expected number of blocks for this file
    int  blockSize;    // Number of bytes per block
    int  num_writes;   // actual number of writes
    char fill_char;    // for each byte
    clock_t  time_done;
    int  thread_done;  // 1 is running, 0 is stopped

};

void A_Writing_Thread(struct ThreadParameterBlock *TPB)
{
     // each thread has its own stack
     FILE *fd;

     int i;

     char *block;

     block = (char *) malloc(TPB->blockSize);
     if (block != NULL)
     {
       memset(block, TPB->fill_char, TPB->blockSize);

       fd = fopen(TPB->fname, "w");

       if (NULL == fd)
       {
          fprintf(stderr, "ERROR: FAILED TO OPEN FILE %s\n", TPB->fname);
       } else {

           for (i = 0; i < TPB->numBlocks; i++)
           {
              // to help demo parallelism of threads,
              // some threads run slow
              if (i%10 == 0)
              {
                  if (TPB->threadNr == 1)     {Sleep(50L);}
                  if ((TPB->threadNr%2) == 0) {Sleep(100L);}
                  if ((TPB->threadNr%3) == 0) {Sleep(200L);}
                  // glad I'm NOT thread 6!
              }
              fwrite(block, sizeof(TPB->blockSize), 1, fd);
              TPB->num_writes++;
           }

       }

       if (fd != NULL) {fclose(fd);}

       free(block);
     }

     printf("\nThread %d done.", TPB->threadNr);

     TPB->time_done   = clock();
     // only exit is thru this code...
     // thread done
     TPB->thread_done = 1;

     _endthread();
}

main()
{

    int numOfThreads = 0;
    int sizeOfDisk = 0;

    int nr_blocks;

    int thread_done_count;

    int blockSize = 4096;

    char ch = 'A';

    int i;

    // allow up to 10 threads
    struct ThreadParameterBlock *thread_array[10];
    struct ThreadParameterBlock *TPB;

    printf("Enter: Size of Disk(MB) white_space  number_of_threads press enter :");
    fflush(stdout);

    scanf("%d %d", &sizeOfDisk, &numOfThreads);

    if (sizeOfDisk < 0)  {sizeOfDisk = 1;}
    if (sizeOfDisk > 10) {sizeOfDisk = 10;}

    if (numOfThreads < 0)  {numOfThreads = 1;}
    if (numOfThreads > 10) {numOfThreads = 10;}

    nr_blocks = (sizeOfDisk * 1024 * 1024) / (numOfThreads * blockSize);
    printf("\ncreating %d threads to allocate %d blocks of 4096 bytes, per thread/file.\n",
                  numOfThreads, nr_blocks);
    fflush(stdout);

    for (i = 0; i < numOfThreads; i++)
    {
        thread_array[i] = TPB = (struct ThreadParameterBlock *)
                                    malloc(sizeof(struct ThreadParameterBlock));

        TPB->threadNr    = i + 1;
        TPB->time_done   = 0;
        TPB->thread_done = 0;
        TPB->numBlocks   = nr_blocks;
        TPB->blockSize   = blockSize;
        TPB->num_writes  = 0;
        TPB->fill_char   = ch++;
        sprintf(TPB->fname, "output%02d.bin", i+1);

        printf("\nstarting thread %d", i+1);
        fflush(stdout);

        /* On first loops, launch character threads. */
        _beginthread(A_Writing_Thread, 0, thread_array[i]);

    }

    // essentially a join...
    while (1)
    {
       /* Wait one second between polls of threads */
       Sleep( 250L );

       thread_done_count = 0;
       for (i = 0; i < numOfThreads; i++)
       {
           thread_done_count += thread_array[i]->thread_done;
       }

       if (thread_done_count >= numOfThreads) {break;}

    }

    printf("\nAll threads are done.");

    printf("\n\nThread Summary");
    for (i = 0; i < numOfThreads; i++)
    {
        printf("\nThread %2d completed %4d writes(%dkB) at %5d to <%s>.",         thread_array[i]->threadNr,
                thread_array[i]->num_writes,
                (thread_array[i]->num_writes*thread_array[i]->blockSize) / 1024,
                thread_array[i]->time_done,
                thread_array[i]->fname);

        // free parameter block for thread i
        free(thread_array[i]);
    }

} // end main;

希望这能有所帮助。如果还有更多的问题,请提问。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18068455

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档