c - 在C中使用互斥锁同步pthread

标签 c linux multithreading mutex

我得写一个程序来计算由公式(x^i)/i给出的前10个项的系列(对不起,我的语言,这是我第一次用英语谈论数学)!。所以,基本上是微不足道的。但是,有一些特殊的要求。每一个术语都要通过单独的线程进行计数,每个线程同时工作。然后他们都把结果保存到名为result的公共变量中。之后,它们必须由主线程添加,主线程将显示最终结果。所有这些都使用pthread和mutex。
这就是我有问题的地方。我想用表来存储结果,但老师告诉我,这不是正确的解决方案,因为这样我就不必使用互斥体了。有什么办法和如何同步吗?我对pthread和mutex完全不熟悉。
这是我到现在为止得到的。我还在努力,所以目前还没有成功,这只是一个程序方案,我想在其中添加互斥。我希望这不全是错的。;页

#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 in term),然后程序仍在工作,什么也不显示。printf评论道,while循环是无限的。局部变量final也只有result的最后一个值。我做错什么了?

最佳答案

主线程应该是添加术语的线程,这是人为的,但是各个线程都必须将其结果写入同一个变量。我通常希望每个线程向结果中添加自己的术语(这确实需要互斥),或者可能将其结果放入数组(如您所建议的那样),或者将其添加到共享队列(这将需要互斥),甚至将其写入管道。尽管如此,这还是可以按照你老师的方式来做。
要解决的一个关键问题是,必须对需要同步的操作进行明显不同的操作:
各种计算线程对共享结果变量的写入
主线程读取结果变量
不能只使用一个同步构造,因为这样就无法区分计算线程和主线程。一种方法是根据需要通过互斥锁同步计算线程的写操作,并通过信号量或条件变量与主线程的读操作进行同步。您也可以使用一个或多个额外的互斥体来完成这项工作,但这并不干净。
附加说明:
线程存放其条款的结果变量必须是全局变量。线程无法访问从中启动它们的函数的局部变量。
term()函数的签名对于线程启动函数不正确。参数的类型必须为void *
线程启动函数与其他函数没有区别,因为它们的局部变量只能在函数执行期间访问。特别是,返回一个指向局部变量的指针不能做任何有用的事情,因为以后试图取消对此类指针的引用都会产生未定义的行为。
我不打算为你写作业,但这里有一个可行的方法:
主线程初始化一个互斥锁和两个信号量,后者的初始值为零。
主线程启动所有计算线程。虽然它很难看,但是您可以通过将其数值参数转换为void *,然后将其转换回term()函数(因为它的参数应该是void *)来为它们提供数值参数。
然后主线程循环。在每次迭代中
等待信号量1(sem_wait()
将全局result变量的值添加到运行总数中
发送到信号灯2(sem_post()
如果执行的迭代次数与执行的线程数量相同,则中断循环
同时,每个计算线程都执行以下操作:
计算适当术语的值
锁定互斥锁
将术语值存储在全局变量中
到信号灯1的标杆
等待信号量2
解锁互斥锁
更新
要为此作业使用条件变量,必须标识哪些共享状态受这些条件变量保护,因为必须始终防止条件变量因等待而虚假唤醒。
在这种情况下,所讨论的共享状态自然会涉及全局result变量,计算线程在该变量中返回其结果。这个变量实际上有两种通用的、相互排斥的状态:
准备好从计算线程接收值,并且
准备好让主线程读取。
计算线程需要等待第一个状态,而主线程需要(重复)等待第二个状态。由于线程需要等待两个不同的条件,因此需要两个条件变量。以下是使用这些想法的另一种方法:
主线程初始化一个互斥锁和两个条件变量,并将result设置为result
主线程启动所有计算线程。虽然它很难看,但是您可以通过将其数值参数转换为-1,然后将其转换回void *函数(因为它的参数应该是term())来为它们提供数值参数。
主线程锁定互斥锁
然后主线程循环。在每次迭代中
测试void *是否为非阴性。如果是的话
result变量的值添加到运行总数中
如果添加的术语与线程的数目一样多,则会中断循环
result设置为result
信号条件变量1
等待条件变量2
从循环中断后,主线程将解锁互斥锁
同时,每个计算线程都执行以下操作:
计算其期限
锁定互斥锁
循环:
检查-1的值。如果小于零,则从循环中断
等待条件变量1
从循环中断后,将result设置为计算项
信号条件变量2
解锁互斥锁

关于c - 在C中使用互斥锁同步pthread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30414090/

相关文章:

Java synchronized() 关键字——防止字段中引用的对象发生变化?

java - 局部变量线程安全吗?

c - 使用 fread 附加到缓冲区

GDB 可以帮助找出内存地址何时被释放吗?

linux - 使用 "gcc $(pkg-config --cflags --libs glib-2.0) context.c"编译时出错 -> <galloca.h> 未找到

linux - 如何设置 crontab 每 10 分钟删除 linux 上日志文件的内容

xml - 如果使用标准 linux 工具包含特定字符串,如何从 xml 文件中提取整个记录

c - 如果不存在则创建虚拟表的替代方法

无法在 Eclipse 中使用 gcc -shared 找到库来构建 dll

.net - .net哈希表插入失败。负载系数太高