我编写了一个程序,使用pthread创建了许多文件。例如,如果我传递“./ioload110”,这个程序应该创建总共占用1MB磁盘空间的10个文件(即output0、output1、...、output9)。但是,当我运行该程序时,它无法在执行后创建所有10个文件。我想知道是什么导致了这个问题?
#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);
}
}发布于 2013-08-06 05:58:09
每个线程都会被传递一个指向ibuffer的指针。对于主线程循环的每次迭代,ibuffer很可能都有相同的地址,这意味着所有线程都试图从同一内存中读取数据。
不能保证每个新线程都会被调度,并且会在主线程开始其循环的下一次迭代之前创建文件,从而更新ibuffer的内容。这可能会导致多个线程尝试创建相同的文件,或者一些线程在稍后的snprintf调用过程中尝试读取它们的文件名。
要解决此问题,您需要让每个线程发出已完成构造的信号,或者在主线程中存储一个文件名数组,将一个指向不同实例的指针传递到每个线程中。
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);
}
}
....发布于 2013-08-06 07:34:37
感谢您的提问,我已经在C#中开发了线程,所以这是一篇关于实现C/WIN32线程的很好的评论。
首先要注意的是,这段代码是使用Microsoft C编译器为Windows机器编写的。对于*nix系统,您需要执行类似的操作,但调用和宏名称不同。然而,一般原则是相同的。
main()中初始化所有线程后,等待它们完成。使用信号量测试完成。对于Windows,您需要使用线程安全库,但它看起来像XP或更高版本的任何系统都提供线程安全的DLL,如msvcrt.lib。此外,还有一个_begintheadex版本,它有更多的功能,并被推荐。
最后,这段代码还不能在实际的应用程序中使用。它还需要做很多事情(比如使用_beginthreadex),但为了讨论的目的,这是一个很好的开始。
// 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;希望这能有所帮助。如果还有更多的问题,请提问。
https://stackoverflow.com/questions/18068455
复制相似问题