[英]Synchronizing pthreads using mutex in C
我必须编写一个程序,该程序计算由公式(x ^ i)/ i!给出的前10个术语(对不起,对于我的语言,这是我第一次谈论英语数学)。 因此,基本上这是微不足道的。 但是,有一些特殊要求。 每个单独的术语都必须由单独的线程计算,每个线程并发工作。 然后他们都将结果保存到名为result的公共变量中。 之后,必须通过主线程添加它们,这将显示最终结果。 所有这些都使用pthread和互斥锁。
那就是我有问题的地方。 我当时在考虑使用表来存储结果,但是老师告诉我,这不是正确的解决方案,因为这样我就不必使用互斥体了。 有什么想法怎么做以及如何使其同步? 我对pthread和互斥锁是完全陌生的。
这就是我到目前为止所得到的。 我仍在处理它,因此目前无法使用,这只是一个程序的方案,我想在其中添加互斥体。 我希望这不是全部错误。 ,p
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
int number = 0;
float result = 0;
pthread_mutex_t term_lock;
pthread_mutex_t main_lock;
int save = 0; //condition variable
int factorial(int x) {
if(x==0 || x==1)
return 1;
return factorial(x-1)*x;
}
void *term(void *value) {
int x = *(int *)value;
float w;
if(save == 0) {
pthread_mutex_lock(&term_lock);
w = pow(x, number)/factorial(number);
result = w;
printf("%d term of series with x: %d is: %f\n", number, x, w);
number++;
save = 1;
pthread_mutex_unlock(&term_lock);
}
return NULL;
}
int main(void) {
int x, i, err = 0;
float final = 0;
pthread_t threads[10];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
printf("Get X: \n");
scanf("%d", &x);
for(i=0; i<10; i++)
{
err = pthread_create(&threads[i], &attr, (void *)term, &x);
if(err) {
printf("Error creating threads.\n");
exit(-1);
}
}
i = 0;
while (number <= 10) {
//printf("While Result: %f, final %f\n", result, final); - shows that it's infinite loop
if(save) {
pthread_mutex_lock(&main_lock);
final = final + result;
save = 0;
pthread_mutex_unlock(&main_lock);
printf("If Result: %f, final %f\n", result, final); //final == last result
}
}
return 0;
}
编辑:如果不清楚-我需要解决方案的帮助,该解决方案如何将所有线程的结果存储在公共变量中并进行同步。
EDIT2:可能的解决方案-所有线程共享全局变量result
。 返回主线程后,它将被添加到一些局部变量中,因此我可以用另一个线程的结果覆盖它的值。 当然,这将需要一些同步,因此在我将其添加到主线程之前,另一个线程不会覆盖它。 你怎么看?
EDIT3:我已经用现在的内容更新了代码。 输出给我的值是8-9项(以printf表示),然后程序仍在工作,什么也没显示。 评论过的printf向我展示了while循环是无限的。 同样,局部变量final具有结果的最后一个值。 我究竟做错了什么?
相当虚构的是,主线程应该是添加术语的线程,但是各个线程必须全部将其结果写入同一变量。 我通常希望每个线程在结果中添加自己的条件(这确实需要互斥体),或者可能将其结果放入数组中(如您建议的那样),或者将其添加到共享队列中(这需要互斥体) ,甚至将其写入管道。 不过,可以按照您老师的方式完成。
要解决的关键问题之一是您必须进行完全不同的同步操作:
您不能仅使用单个同步构造,因为您不能通过这种方式在计算线程和主线程之间进行区分。 解决此问题的一种方法是根据需要通过互斥锁同步计算线程的写入,并与vs同步。 主线程通过信号量或条件变量进行读取。 您也可以使用一个或多个其他互斥锁来做到这一点,但并非一帆风顺。
补充笔记:
term()
函数的签名对于线程启动函数不正确。 参数必须为void *
类型。 我不会为您写作业,但这是一种可行的方法:
void *
,然后将其强制返回term()
函数(因为其参数应为void *
)来为其提供数字参数。 sem_wait()
) result
变量的值添加到运行总计 sem_post()
) 同时,每个计算线程都这样做:
result
变量中 更新:
要使用条件变量来完成这项工作,必须确定那些条件变量正在保护哪个共享状态,因为必须始终防止他人因等待条件变量而突然醒来。
在这种情况下,看起来很自然,所讨论的共享状态将包含全局result
变量,计算线程将在其中返回其结果。 该变量实际上有两个通用的互斥状态:
计算线程需要等待第一个状态,而主线程需要(重复)等待第二个状态。 由于线程需要等待两个不同的条件,因此需要两个条件变量。 这是使用这些想法的另一种方法:
result
设置为-1
。 void *
,然后将其强制返回term()
函数(因为其参数应为void *
)来为其提供数字参数。 result
是否为负数。 如果是这样
result
变量的值添加到运行总计 result
设置为-1
。 同时,每个计算线程都这样做:
result
的值。 如果小于零,则从循环中断 result
设置为计算项 该number
在所有线程之间共享,因此您需要使用互斥锁来保护它(这可能是您的老师希望看到的)
pthread_mutex_t number_mutex;
pthread_mutex_t result_mutex;
int number = 0;
int result = 0;
void *term(int x) {
float w;
// Critical zone, make sure only one thread updates `number`
pthread_mutex_lock(&number_mutex);
int mynumber = number++;
pthread_mutex_unlock(&number_mutex);
// end of critical zone
w = pow(x, mynumber)/factorial(mynumber);
printf("%d term of series with x: %d is: %f\n", mynumber, x, w);
// Critical zone, make sure only one thread updates `result`
pthread_mutex_lock(&result_mutex);
result += w;
pthread_mutex_unlock(&result_mutex);
// end of critical zone
return (void *)0;
}
您还应该删除DETACHED状态,并在输出结果之前在主程序的末尾进行线程联接。
这是我为您解决的问题:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
int number=0;
float result[10];
pthread_mutex_t lock;
int factorial(int x) {
if(x==0 || x==1)
return 1;
return factorial(x-1)*x;
}
void *term(void *value) {
int x = *(int *)value;
float w;
pthread_mutex_lock(&lock);
w = pow(x, number)/factorial(number);
printf("%d term of series with x: %d is: %f\n", number, x, w);
result[number] = w;
number++;
pthread_mutex_unlock(&lock);
return NULL;
}
int main(void) {
int x, i, err;
pthread_t threads[10];
printf("Get X: \n");
scanf("%d", &x);
for(i=0; i<=9; i++)
{
err = pthread_create(&threads[i], NULL, term, &x);
if(err) {
printf("Error creating threads.\n");
exit(-1);
}
}
for(i = 0; i < 10; i++)
{
pthread_join(threads[i], NULL);
}
i = 0;
for(i=0; i<=9; i++)
{
printf("%f\n", result[i]);
}
return 0;
}
此代码创建一个全局互斥锁pthread_mutex_t lock
(在这种情况下)确保任何人都不会同时执行相同的代码:基本上,当一个线程执行pthread_mutex_lock(&lock)
,它将禁止任何其他thread
执行该部分代码。直到“原始”线程执行pthread_mutex_unlock(&lock)
为止。
另一个重要的部分是pthread_join
:强制主线程等待创建的所有其他线程的执行。 这样,在实际在主线程中进行处理之前(在此情况下,最后一条打印指令),将写入float result[10]
。
除此之外,我修复了其他用户指出的代码中的一些错误。
如果结果是单个变量,则一种解决方案是使用20个互斥量的数组:aMutex [20];。 Main锁定所有20个互斥锁,然后启动pthread。 每个pthread [i]计算一个本地项,等待aMutex [i],将其值存储到结果中,然后解锁aMutex [10 + i]。 在main()中,for(i = 0; i <20; i ++){解锁aMutex [i]以允许pthread [i]将其值存储到结果中,然后等待aMutex [10 + i]知道结果已更新,然后将结果相加。 }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.