2013-08-23 36 views
1

在下面的代码中,我只是想看看我是否能够从每个线程插入一个元素到数组中。它按预期工作。但后来我想知道,在什么情况下,这里可能会出现竞赛状况。我真的需要在这里变动吗,还是信号量?我试图删除信号量和易变的关键字,仍然有效。我想在这里引发并看到竞赛情况。在同一行上,我可以从每个线程创建一个节点,并将所有节点放入链接列表中?这些都是虚构的场景..!C多线程:竞态条件场景

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <semaphore.h> 
#include "small_appl.h" 

void * thread_func(void * arg); 

int itr=0; 
volatile int idx=0; //array index variable 
sem_t sem1; 
int arr_th[5];  //array where each thread will insert an element 

int func_pointed(int a,int num_t) 
{ 
    pthread_t arr_thr[num_t]; 
    int iter; 
    //create threads 
    for(iter=0;iter<num_t;iter++) 
    { 
     pthread_create(&arr_thr[iter],NULL,thread_func,(void *)a); 
    } 

    for (iter=0;iter<num_t;iter++) 
    { 
     pthread_join(arr_thr[iter],NULL); 
    } 
} 

int main(void) 
{ 
    int ip1=5,ip2=10,rev; 

    rev=sem_init(&sem1,0,0); 
    s_type dev_s={ 
        .f_ptr=func_pointed, 
        .str="Diwakar", 
        .val=5 
       }; 

    //initialize semaphore to 1 
    sem_post(&sem1);  

    func_aux(ip1,dev_s); 

    for(rev=0;rev<5;rev++) 
    { 
    printf("array : %d ",arr_th[rev]); 
    } 

} 

void * thread_func(void * arg) 
{ 
    sem_wait(&sem1); 
    printf("Got sema\n"); 
    arr_th[idx]=itr; 
    idx++; itr++; 
    printf("Releasing sema\n"); 
    sem_post(&sem1); 

    sleep(5); 
} 
+4

在C中,'volatile'并不意味着你的想法。特别是,它不同于一个原子变量或任何进行内存同步的东西。 –

+0

竞态条件不容易产生。C语言中的volatile只是为了告诉编译器不要为这个变量优化,而不是为了多线程目的。 – JackyZhu

+0

在此代码中,您不需要任何位置的“volatile”*。你也不需要信号量,因为无论如何你真正使用它是一个互斥量(如果你抛出信号量,你就需要*)*。 – WhozCraig

回答

1

要创建或模仿其中线程覆盖另一个线程所做的工作的情况,然后取出信号和战略上放置的睡眠,如:

void * thread_func(void * arg) 
{ 
    //sem_wait(&sem1); 
    //printf("Got sema\n"); 
    arr_th[idx]=itr; 
    // print arr_th[idx] 
    sleep(5);  <<== gives the threads more of a chance to wipe-out each other 
    // print arr_th[idx] 
    idx++; itr++; 
    //printf("Releasing sema\n"); 
    //sem_post(&sem1); 

    sleep(5); 
} 

您可以添加一些printf语句明确突出问题。

volatile告诉编译器不要删除未使用或至少看起来未被使用的变量。

您可以从多个线程更新链接列表,但必须序列化更新列表中链接(next和/或prev)的代码的关键部分。

在Windows XP及以上版本中,CRT是线程安全的,因此每个线程都可以发出malloc(),printf之类的内容,而不必序列化这些调用的线程。

+0

你能否给我提供一些关于序列化关键部分意味着什么的提示? –

+0

@DiwakarSharma,基本思想是只允许一个线程在任何时候运行一小段指令。记住所有的线程通常运行相同的代码,但是它的某些部分只允许一个线程执行它。搜索互斥锁或信号量,并调用系统函数来完成此操作。但是,如果您了解信号量的概念,那么您可以编写自己的序列化代码。要解释更多内容需要一章,但要了解信号量的概念以及如何用C代码实现。 – JackCColeman

1

volatile指示编译器该变量随时可以更改。这意味着对变量的每个引用都必须导致从内存中读取(而不是重用寄存器中的值的副本)。

volatile int i; 
if(i==0) return 
if(i==1) ... 

如果volatile关键字是不存在,编译器可能会读取变量到寄存器一次,并检查它的0和1

如果你的主程序您等待IDX变量是一定的价值是这样的,你应该让它volatile

while(idx==10); 

挥发性不会使它线程安全,这是一个不同的问题。事实上,因为你保护了这段代码,所以你不希望idx从一次读取变为下一次,所以你不需要volatile。

如果你想产生竞争条件(检测部分代码被拆分),我建议设置2个值,你在2个单独的指令中增加,并在一个连续的while循环(不睡觉!减少关键部分分裂的可能性)。在主循环中,不断检查值是否相等(再次不睡觉)。如果它们不相等,则代码的两个部分之一被拆分。还要看看程序集以确保编译器没有优化某些东西。