【问题标题】:Trying to understand Race Conditions/Threads in C试图理解 C 中的竞争条件/线程
【发布时间】:2018-03-17 21:46:14
【问题描述】:

对于陈述者,我是一名学生,不是 CS 本科生,但正在转入 CS 硕士课程。因此,我欢迎任何人愿意提供的任何帮助。

这样做的目的是在 2-4 之间创建 N 个线程,然后使用随机生成的小写字符数组,将它们变为大写。

这需要使用 N 个线程(在执行时由命令行定义)来完成,使用 pthread 尽可能均匀地划分工作。

我想问的主要问题是,我是否避免了线程之间的竞争条件?

我也很难理解在线程之间划分工作。据我了解(如果我错了,请纠正我),通常在执行过程中会随机选择运行的线程。所以,我假设我需要按照在 N 个线程中动态划分数组并设置它以便每个线程执行数组的相同大小子部分的大写操作?

我知道我的代码中可能还有许多其他差异需要改进,但我编写代码的时间不长,大约一个月前才开始使用 C/C++。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <ctype.h>

//Global variable for threads
char randChars[60];
int j=0;

//Used to avoid race conditions
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;

//Establish the threads
void* upperThread(void* argp)
{
    while(randChars[j])
    {
        pthread_mutex_lock( &mutex1 );
        putchar (toupper(randChars[j]));
        j++;
        pthread_mutex_unlock( &mutex1 );
    }

return NULL;

}

int main(int argc, char **argv)
{
    //Initializae variables and thread
    int N,randNum,t;
    long i;
    pthread_t pth[N];
    pthread_mutex_init(&mutex1, NULL);
    char randChar = ' ';

    //Check number of command inputs given
    if(argc!=2)
    {
        fprintf(stderr,"usage: %s <enter a value for N>\n", argv[0]);
        exit(0);
    }

    N = atoi(argv[1]);

    //Checks command inputs for correct values
    if(N<2||N>4){
        printf("Please input a value between 2 and 4 for the number of threads.\n");
        exit(0);
    }

    //Seed random to create a randomized value
    srand(time(NULL));
    printf("original lower case version:\n");

    for (i=0; i<61; i++)
    {
        //Generate a random integer in lower alphabetical range
        randNum = rand()%26;
        randNum = randNum+97;

        //Convert int to char and add to array
        randChar = (char) randNum;
        randChars[i] = randChar;
        printf("%c", randChar);
    }

    //Create N threads
    for (i=0; i<N; i++)
    {
        pthread_create(pth + i, NULL, upperThread, (void *)i);
    }

    printf("\n\nupper case version:\n");

    //Join the threads
    for(t=0; t < N; t++)
    {
        pthread_join(pth[t], NULL);
    }
    printf("\n");

    pthread_exit(NULL);

    return 0;
}

【问题讨论】:

  • 这种尝试是徒劳的。所有线程都在尝试修改同一个对象,并且会不断地互相踩踏。结果将是您的代码几乎将所有时间都用于协调线程,而几乎没有时间做实际有用的工作。
  • 我担心可能是这样,因为他们似乎都试图一起做同样的事情。不过谢谢。
  • 线程在任何锁之外访问全局变量j,这是一个竞争条件。如果您希望线程每个都对数组的不同/不相交的子集进行操作,那么最好的方法是向每个线程传递您希望它操作的最小和最大索引值;然后每个线程可以并行运行,不需要互斥锁(并且没有竞争条件,因为它们不访问任何共享变量)

标签: c multithreading pthreads


【解决方案1】:

您提供的示例不是一个好的多线程程序。原因是您的线程将不断等待持有锁的线程。这基本上使您的程序顺序。我会将您的 upperThread 更改为

void* upperThread(void* argp){
    int temp;
    while(randChars[j]){
            pthread_mutex_lock( &mutex1 );
            temp = j;     
            j++;
            pthread_mutex_unlock( &mutex1 );

            putchar (toupper(randChars[temp]));
        }

    return NULL;

}

这样,您的线程将等待持有锁的线程,直到它提取 j 的值,将其递增并释放锁,然后执行其余操作。

一般规则是只有在处理关键部分关键数据时才需要获取锁,在这种情况下,它是字符串的索引。阅读关键部分和比赛条件here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-21
    • 2014-02-23
    • 2013-08-26
    • 1970-01-01
    • 1970-01-01
    • 2016-10-12
    相关资源
    最近更新 更多