CLHLock的C语言实现

来源:互联网 发布:四知的学法指导 编辑:程序博客网 时间:2024/06/06 02:15
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>

#define FALSE 0
#define TRUE 1

static int shareddata = 50;
struct qnode* tail;
struct qnode q;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

/*相当于Java的ThreadLocal*/

pthread_key_t myNode;
pthread_key_t myPred;


typedef struct qnode
{
    int locked;
}QNode;


/*线程的参数*/

typedef struct arg
{
    int t_id;
    QNode qnode;
    QNode* myNode;
    QNode* myPred;

}Arg;


/*将线程与其参数绑定*/
typedef struct thread
{
    pthread_t t;
    Arg arg;
}Thread;

QNode* getAndSet(QNode* qnode)
{
    pthread_mutex_lock(&mutex);

    QNode* pred = tail;
    tail = qnode;

    pthread_mutex_unlock(&mutex);
    return pred;
}

int isLock()
{
    int ret;
    QNode* qnode = (QNode*)pthread_getspecific(myPred);
    if (qnode == NULL)
      return  FALSE;

    return (qnode->locked)?TRUE:FALSE;

}

void lock()
{
/*得到线程的私有变量。*/
    QNode* qnode = (QNode*)pthread_getspecific(myNode);
    qnode->locked = TRUE;
    QNode* pred = getAndSet(qnode);
    pthread_setspecific(myPred, pred);


    while(pred->locked)
    {
    }

}


void unlock()
{
    QNode* qnode = (QNode*)pthread_getspecific(myNode);
    qnode->locked = FALSE;
    QNode* pred = (QNode*)pthread_getspecific(myPred);
    pthread_setspecific(myNode, pred);
}


void initCLHlock()
{
    q.locked = FALSE;
    tail = &q;
}

void initThread(Thread* t, int i)
{
    t->arg.qnode.locked = TRUE;
    t->arg.myNode = &(t->arg.qnode);
    t->arg.myPred = NULL;
    t->arg.t_id = i;
}

void* run(Arg* t_arg)

{

/*设置线程的私有变量。此时已经在某一个线程内部,所以会自动的建立map。*/

    pthread_setspecific(myNode, t_arg->myNode);
    pthread_setspecific(myPred, t_arg->myPred);

    while (1)
    {
        /*lock*/
        lock();
        if (shareddata > 0)
        {
            printf("%d get %dth ticket\n", t_arg->t_id, shareddata);
            if (isLock())
              printf("locked!\n");
            shareddata--;
            /*unlock*/
            unlock();
        }
        else
        {
            /*unlock*/
            unlock();
            break;
        }
    }
}
void main()
{
    clock_t start, end;
    Thread t[10];
    initCLHlock();
    pthread_key_create(&myNode, NULL);
    pthread_key_create(&myPred, NULL);


    int i;
    for (i=0; i<4; i++)
    {
        initThread(&t[i], i);
    }

    /*start*/
    start = clock();
    for (i=0; i<4; i++)

    {

/*创建并执行线程,参数是最后一个参数*/

        int ret = pthread_create(&t[i].t, NULL, (void*)run, &t[i].arg);
        if (ret != 0)
        {
            printf("creat_thread error!\n");
            exit(0);
        }
    }

    /*join*/
    for (i=0; i<4; i++)
    {
        pthread_join(t[i].t, NULL);
    }
    end = clock();

    printf("shareddata:%d\n", shareddata);
    printf("speed %f seconds\n", (double)(end-start)/CLOCKS_PER_SEC);
}

关于pthread_key_t

这个其实是一个hash。每一个pthread_key_t代表一个全局的线程私有变量。也就是说,变量虽然是全局的,但是线程里面对他的改变只改变在线程内部的那个copy。这样做的原因是:因为线程使用的数据都是以参数的形式传进去,这些参数肯定是在线程外部,但是有时候这些变量的该表不需要通知其他线程,仅仅是线程自己使用。像上面这个例子,每个线程只关心自己的myNode与myPred两个指针的指向,而不关心其他线程这两个指针的指向,所以在这种情况下,将两个变量作为线程私有会加快速度。在pthread_getspecific与pthread_setspecific时,通过hash查找到对应的值。


0 0
原创粉丝点击