我尝试使用线程制作文件复制器,不知何故,程序在进入函数时锁定。我搜索了很多,我尝试了很多东西,但我根本找不到解决方案。如果有人可以帮助我,我会很高兴的!
//gcc -o threadcopyfile threadcopyfile.c -lpthread -lrt
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //init mutex
pthread_cond_t condRead = PTHREAD_COND_INITIALIZER; //init cond. variables
pthread_cond_t condWrite = PTHREAD_COND_INITIALIZER; //init cond. variables
int n, x = 1, i = 0, j, condition = 0;
char c;
pthread_t pRead;
pthread_t pWrite;
char ringpuffer[10000];
void *functionRead(void *argv){
char **args = (char **) argv; //Give args the arguments from argv
FILE* fp;
if ((fp=fopen(args[1], "r")) == NULL){ //Open the inputfile, check if failed
perror("fopen\n");
exit(EXIT_FAILURE);
}
n = atoi(args[3]);
printf("Entered functionRead\n");
do{
pthread_mutex_lock(&mutex); //Lock mutex
while(condition == 1){
pthread_cond_wait(&condRead, &mutex); //Wait for cond_signal
}
i = 0;
for(i = 0; i<=n; i++){ //Put chars into the ringbuffer
c = fgetc(fp);
ringpuffer[i] = c;
i++;
}
x++;
printf("Hit!");
condition = 1;
pthread_mutex_unlock(&mutex); //Unlock mutex
pthread_cond_signal(&condWrite); //Send signal to CondWrite
}while ((c=fgetc(fp)) != EOF);
if ((fclose(fp)) == EOF){ //Close the file
perror("fclose\n");
exit(EXIT_FAILURE);
}
return 0;
}
void *functionWrite(void *argv){
char **args = (char **) argv; //Give args the arguments from argv
FILE* fp;
if ((fp=fopen(args[2], "w")) == NULL){ //Open the outputfile, check if allowed
perror("fopen\n");
exit(EXIT_FAILURE);
}
n = atoi(args[3]);
printf("Entered functionWrite\n");
for (j = 0; j < x; j++){
pthread_mutex_lock(&mutex); //Lock mutex
while(condition == 0){
pthread_cond_wait(&condWrite, &mutex); //Wait for singel from condRead
}
fwrite(ringpuffer, 1, n, fp); //Write to file
printf("Hit too!");
condition = 0;
pthread_mutex_unlock(&mutex); //Unlock
pthread_cond_signal(&condRead); //Send signal again to condRead
}
if ((fclose(fp)) == EOF){
perror("fclose\n");
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
if (argc != 4){
printf("Only 3 parameters allowed!\n");
exit(EXIT_FAILURE);
}
printf("File to Copy: %s\nTarget: %s\nHow many chars: %s\n", argv[1], argv[2], argv[3]);
pthread_create(&pWrite, NULL, &functionWrite, ((void *)argv)); //Create thread, threadid in pWrite, execute functionWrite, and give argv as arguments
pthread_create(&pRead, NULL, &functionRead, ((void *)argv)); //Create thread, threadid in pRead, execute functionRead and give argv as arguments
printf("Threads created, file copy in progress\n");
pthread_cond_signal(&condRead); //Unblocks the thread
pthread_join(pRead, NULL);
pthread_join(pWrite, NULL);
printf("done.\n");
return 0;
}
答案 0 :(得分:2)
您不能使用具有两个条件变量的单个互斥锁。如果一个线程调用pthread_cond_signal()
并在第二个线程唤醒之前重新锁定互斥锁,则第二个线程永远无法从pthread_cond_wait()
返回,因为它无法锁定互斥锁。
您似乎也没有设置condition = 1
,因为functionRead()
和functionWrite()
中都有condition = 0
。
答案 1 :(得分:0)
你的主要问题是你的编写器线程的终止条件 - 当读者线程决定退出时,它已经增加x
,因此编写器线程将等待另一次...永远。
你也不应该在while循环的终止条件下再次调用c = fgetc(fp)
,因为你最终会抛弃那里读取的字符。相反,您读取缓冲区的循环可能是:
i = 0;
while (i < n && (c = fgetc(fp)) != EOF) { //Put chars into the ringbuffer
ringpuffer[i] = c;
i++;
}
在这个循环结束时,我们知道:
i
个字符读入缓冲区; 和 i < n
,我们已到达文件结尾并应退出。您可以使用其中第二个点来了解读者线程何时完成,因此整个循环如下所示:
do {
pthread_mutex_lock(&mutex); //Lock mutex
while(condition == 1){
pthread_cond_wait(&condRead, &mutex); //Wait for cond_signal
}
i = 0;
while (i < n && (c = fgetc(fp)) != EOF) { //Put chars into the ringbuffer
ringpuffer[i] = c;
i++;
}
printf("Hit!");
condition = 1;
pthread_mutex_unlock(&mutex); //Unlock mutex
pthread_cond_signal(&condWrite); //Send signal to CondWrite
} while (i == n);
要解决写入程序线程终止的实际问题,可以使用相同的终止条件。但是,我们需要在编写器线程中测试i
时保持锁定,否则它可能会在读取器线程中写入i
。要做到这一点,我们将解锁和锁定移到循环外部(这没关系,因为线程没有持有锁定的唯一时间长度是pthread_cond_wait()
无论如何)。我们还使用i
作为从缓冲区写入的字节数,因为读者线程离开该值的位置是:
pthread_mutex_lock(&mutex); //Lock mutex
printf("Entered functionWrite\n");
do {
while(condition == 0){
pthread_cond_wait(&condWrite, &mutex); //Wait for singel from condRead
}
fwrite(ringpuffer, 1, i, fp); //Write to file
printf("Hit too!");
condition = 0;
pthread_cond_signal(&condRead); //Send signal again to condRead
} while (i == n);
pthread_mutex_unlock(&mutex); //Unlock
完成这些更改后,不再需要j
和x
。
您还可以看到其他几个问题:
n
由作者和读者线程设置,没有锁定。你可以在读者线程中设置它,因为在读者线程执行一次之前,编写者线程不会访问它。
变量c
应该是int
,而不是char
。否则,c
可能永远不会与EOF
进行比较,因为EOF
不一定在char
范围内(这就是为什么fgetc()
返回{{ 1}})。 int
也可以是c
的本地人。
没有必要在主线程中发出functionRead()
信号,因为读者会在等待前测试condRead
。
但也许最根本的是,我认为你可能已经错过了这个练习的重点,因为虽然你有一个名为condition
的数组,但你实际上并没有将它用作环形缓冲区。您没有获得任何并行性 - 您的设计意味着您的线程以锁定步骤运行。我怀疑这个想法是你应该有两个单独的标志 - ringpuffer
和buffer_empty
- 而不是单个&#34;读或写&#34;条件。只要buffer_full
不正确,您的文件阅读器就会运行,并且只要buffer_full
为真,您的文件编写器就会运行,因此对于两个标志都为假的部分时间你可以让两个线程都运行。