1

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

#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

2 回答 2

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告诉编译器不要删除未使用或至少看起来未使用的变量。

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

在 Windows XP 及更高版本中,CRT 是线程安全的,因此每个线程都可以发出等malloc()printf而无需围绕这些调用序列化线程。

于 2013-08-23T05:36:39.800 回答
1

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

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

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

如果在你的主程序中你等待 idx 变量是这样的某个值,你应该做它volatile

while(idx==10);

Volatile 不会使它成为线程安全的,这是一个不同的问题。事实上,因为您保护了那段代码,所以您不希望 idx 从一次读取更改为下一次读取,因此您不需要 volatile。

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

于 2013-08-23T06:02:43.713 回答