繁体   English   中英

在C中使用互斥锁同步pthread

[英]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循环是无限的。 同样,局部变量fi​​nal具有结果的最后一个值。 我究竟做错了什么?

相当虚构的是,主线程应该是添加术语的线程,但是各个线程必须全部将其结果写入同一变量。 我通常希望每个线程在结果中添加自己的条件(这确实需要互斥体),或者可能将其结果放入数组中(如您建议的那样),或者将其添加到共享队列中(这需要互斥体) ,甚至将其写入管道。 不过,可以按照您老师的方式完成。

要解决的关键问题之一是您必须进行完全不同的同步操作:

  • 各种计算线程将写入共享结果变量
  • 主线程读取结果变量

您不能仅使用单个同步构造,因为您不能通过这种方式在计算线程和主线程之间进行区分。 解决此问题的一种方法是根据需要通过互斥锁同步计算线程的写入,并与vs同步。 主线程通过信号量或条件变量进行读取。 您也可以使用一个或多个其他互斥锁来做到这一点,但并非一帆风顺。

补充笔记:

  • 您的线程在其中存放其条件的结果变量必须是全局变量。 线程无权访问从中启动它们的函数的局部变量。
  • 您的term()函数的签名对于线程启动函数不正确。 参数必须为void *类型。
  • 线程启动函数与其他函数没有什么不同,它们的局部变量仅在函数执行期间才可访问。 特别是,将指针返回到局部变量不能做任何有用的事情,因为任何以后取消引用此类指针的尝试都会产生未定义的行为。

我不会为您写作业,但这是一种可行的方法:

  1. 主线程初始化一个互斥锁和两个信号量,后者的初始值为零。
  2. 主线程启动所有计算线程。 虽然很丑陋,但您可以通过将其强制转换为void * ,然后将其强制返回term()函数(因为其参数应为void * )来为其提供数字参数。
  3. 然后主线程循环。 在每次迭代中
    1. 等待信号量1( sem_wait()
    2. 将全局result变量的值添加到运行总计
    3. 张贴到信号量2( sem_post()
    4. 如果执行的迭代次数与线程数相同,则中断循环

同时,每个计算线程都这样做:

  1. 计算适当项的值
  2. 锁定互斥锁
  3. 将术语值存储在全局result变量中
  4. 张贴信号量1
  5. 等待信号量2
  6. 解锁互斥锁

更新:

要使用条件变量来完成这项工作,必须确定那些条件变量正在保护哪个共享状态,因为必须始终防止他人因等待条件变量而突然醒来。

在这种情况下,看起来很自然,所讨论的共享状态将包含全局result变量,计算线程将在其中返回其结果。 该变量实际上有两个通用的互斥状态:

  1. 准备从计算线程接收值,并且
  2. 准备主线程读取。

计算线程需要等待第一个状态,而主线程需要(重复)等待第二个状态。 由于线程需要等待两个不同的条件,因此需要两个条件变量。 这是使用这些想法的另一种方法:

  1. 主线程初始化一个互斥锁和两个条件变量,并将result设置为-1
  2. 主线程启动所有计算线程。 虽然很丑陋,但您可以通过将其强制转换为void * ,然后将其强制返回term()函数(因为其参数应为void * )来为其提供数字参数。
  3. 主线程锁定互斥锁
  4. 然后主线程循环。 在每次迭代中
    1. 测试result是否为负数。 如果是这样
      1. result变量的值添加到运行总计
      2. 如果添加的术语与线程的数量一样多,则中断循环
      3. result设置为-1
      4. 信号条件变量1
    2. 等待条件变量2
  5. 从循环中断后,主线程将互斥锁解锁

同时,每个计算线程都这样做:

  1. 计算其期限
  2. 锁定互斥锁
  3. 循环:
    1. 检查result的值。 如果小于零,则从循环中断
    2. 等待条件变量1
  4. 脱离循环后,将result设置为计算项
  5. 信号条件变量2
  6. 解锁互斥锁

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM