ITKeyword,专注技术干货聚合推荐

注册 | 登录

linux——线程同步(互斥量、条件变量、信号灯、文件锁)

jipingyuan 分享于 2014-08-23

推荐:linux多线程-----同步机制(互斥量、读写锁、条件变量)

linux多线程同步机制主要有:互斥量,读写锁,条件变量。 互斥量: 互斥量用pthread_mutex_t数据类型表示,在使用互斥变量以前,必须对它进行初始化,可以把它设

2018阿里云全部产品优惠券(新购或升级都可以使用,强烈推荐)
领取地址https://promotion.aliyun.com/ntms/yunparter/invite.html

一、说明

linux的线程同步涉及:

1、互斥量

2、条件变量

3、信号灯

4、文件读写锁

信号灯很多时候被称为信号量,但个人仍觉得叫做信号灯比较好,因为可以与“SYSTEM V IPC的信号量”相区分(如有不同意见,欢迎探讨)。

二、互斥量

1、定义

互斥锁允许我们锁住某个对象(某个变量、某段代码等),使得每次只能有一个线程访问他。我们在对需要保护的对象进行操作前,先把互斥锁上锁,如果上锁成功,就不会有别的线程再来操作被保护的对象。如果上锁不成功,线程就会阻塞(可能是有别的线程已经把互斥锁锁住了),直到互斥锁被打开。从而保护了要保护的对象。

2、相关函数

a.pthread_mutex_init

函数原型:

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

功能: 初始化互斥锁

参数: mutex为pthread_mutex_t类型的变量的地址,也就是互斥锁的名字;

mutexattr为pthread_mutexattr_t类型的变量地址,用于设置锁的属性,默认可以设为NULL;

返回: 成功0,错误返回错误代码。

备注: 初始化互斥锁还有个简便的方法,比如对 pthread_mutex_t a; 进行初始化,则直接写成:pthread_mutex_t a = PTHREAD_MUTEX_INITIALIZER; 即可。

b.pthread_mutex_destroy

函数原型:

int pthread_mutex_destroy(pthread_mutex_t *mutex);

功能: 销毁互斥锁

参数: mutex为要销毁的互斥锁的地址

返回: 成功0,错误返回错误代码。

c.pthread_mutex_lock

函数原型:

int pthread_mutex_lock(pthread_mutex_t *mutex));

功能: 上锁

参数: 同上

返回: 同上

d.pthread_mutex_unlock

函数原型:

int pthread_mutex_unlock(pthread_mutex_t *mutex);

功能: 解锁

参数: 同上

返回: 同上

3、例程

#include <stdio.h>
#include <pthread.h>

pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
int cnt=0;


void *func1(void *b)
{
    int a=2000;

    usleep(rand()%2000);
    while(a--)
    {
        printf("11111=%d.\n",a);
        printf("\tpthread 1 start to lock.\n");
        pthread_mutex_lock (&mylock);
        printf("\tpthread 1 locked.\n");
        cnt++;
        printf("\t++cnt=%d\n",cnt);
        printf("\tpthread 1 start to unlock.\n");
        pthread_mutex_unlock (&mylock);
        printf("\tpthread 1 unlocked.\n");
    }
}

void *func2(void *b)
{
    int a=2000;

    usleep(rand()%2000);
    while(a--)
    {
        printf("22222=%d.\n",a);
        printf("\tpthread 2 start to lock.\n");
        pthread_mutex_lock (&mylock);
        printf("\tpthread 2 locked.\n");
        if(cnt>0)
        {
            cnt--;
            printf("\t--cnt=%d\n",cnt);
        }
        printf("\tpthread 2 start to unlock.\n");
        pthread_mutex_unlock (&mylock);
        printf("\tpthread 2 unlocked.\n");
        if(!cnt)
        {
            usleep(1);
        }
    }
}


int main(void)
{
    pthread_t a,b;

    pthread_create(&a, NULL, func1, (void*)0 );
    pthread_create(&b, NULL, func2, (void*)0 );

    pthread_join (a, NULL);
    pthread_join (b, NULL);

    return 0;
}
程序中,cnt即为要保护的对象,两个线程,同一时刻只能有一个线程在访问这个对象。

三、条件变量

1、定义

条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定条件的发生。条件本身受互斥量的保护,线程在改变条件状态前,必须先锁住互斥量,其他线程在获得互斥量之前不会觉察到这种变化(因为互斥量被正在改变条件的线程锁着,其他线程没有获得互斥量就没有机会觉察到变化)

2、相关函数

a.pthread_cond_init

函数原型:

int pthread_cond_init (pthread_cond_t * cond, const pthread_condattr_t *cond_attr);

功能: 初始化条件变量

参数: cond条件变量名的地址

cond_attr为条件变量的属性

返回: 成功0,错误返回错误编号

备注: 简便的初始化方法:pthread_cond_t a = PTHREAD_COND_INITIALIZER;

b.pthread_cond_destroy

函数原型:

int pthread_cond_destroy (pthread_cond_t *cond);

功能: 销毁条件变量

参数: cond条件变量名的地址

返回: 成功0,错误返回错误代码

c.pthread_cond_wait

函数原型:

推荐:线程同步(信号量,互斥,条件变量)

进行多线程编程,最头疼的就是那些共享的数据。因为你无法知道哪个线程会在哪个时候对它进行操作,你也无法得知那个线程会先运行,哪个线程会后运行。下面介绍一

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)

功能: 等待互斥锁mutex下的条件cond的发生

参数: cond为要等待的条件变量

mutex为保护条件变量的互斥锁

返回: 成功0,错误返回错误代码

d.pthread_cond_signal

函数原型:

int pthread_cond_signal (pthread_cond_t *cond);

功能: 发送条件变量cond

参数: cond为要发送的条件变量

返回: 成功0,否则返回错误编号

备注: 只通知某一个等待该条件的线程
e.pthread_cond_broadcast

功能: 发送条件变量cond

参数: cond为要发送的条件变量

返回: 成功0,否则返回错误编号

备注: 通知所有等待该条件的线程

3、例程(与某嵌入式面试题类似:三个线程各自打印A、B、C,要求按顺序ACBCACBC输出)

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

int sequence=1;
int eat = 1;
pthread_mutex_t productor_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t my_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t productor_mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t my_cond1 = PTHREAD_COND_INITIALIZER;

void *productor1()
{
    int my_sequence = 1;
	
    while(1)
    {
        pthread_mutex_lock(&productor_mutex);
        while(sequence!=my_sequence)
        {
            pthread_cond_wait (&my_cond, &productor_mutex);
        }


        pthread_mutex_lock(&productor_mutex1);
        while(eat!=1)
        {
            pthread_cond_wait (&my_cond1, &productor_mutex1);
        }
        printf("A ");

        eat=0;
        pthread_cond_broadcast (&my_cond1);
        pthread_mutex_unlock (&productor_mutex1);

        sequence=2;
        pthread_cond_broadcast(&my_cond);
        pthread_mutex_unlock (&productor_mutex);
    }
			
    return 0;
}

void *productor2()
{
    int my_sequence=2;
	
    while(1)
    {
        pthread_mutex_lock(&productor_mutex);
        while(sequence!=my_sequence)
        {
            pthread_cond_wait (&my_cond, &productor_mutex);
	}

        pthread_mutex_lock(&productor_mutex1);
        while(eat!=1)
        {
	    pthread_cond_wait (&my_cond1, &productor_mutex1);
        }
        printf("B ");

        eat=0;
        pthread_cond_broadcast (&my_cond1);
        pthread_mutex_unlock (&productor_mutex1);

        sequence=1;
        pthread_cond_broadcast (&my_cond);
        pthread_mutex_unlock (&productor_mutex);
    }
			
    return 0;
}

void *consumer()
{
    long a=200;

    while(a--)
    {
        pthread_mutex_lock(&productor_mutex1);
        while(eat!=0)
        {
            pthread_cond_wait (&my_cond1, &productor_mutex1);
        }
        printf("C ");

        eat=1;
        pthread_cond_broadcast (&my_cond1);
        pthread_mutex_unlock (&productor_mutex1);
    }
	
	return 0;
}

int main(void)
{
	pthread_t pth1=0,pth2=0,pth3=0;
	int err=-1;
	void *tret=NULL;

	err = pthread_create(&pth1,NULL,productor1,NULL);
	if(err)
	{
		printf("creat pthread productor failed!\n");
		exit(1);
	}
	err = pthread_create(&pth2,NULL,productor2,NULL);
	if(err)
	{
		printf("creat pthread productor failed!\n");
		exit(1);
	}

	err = pthread_create(&pth3,NULL,consumer,NULL);
	if(err)
	{
		printf("creat pthread consumer failed!\n");
		exit(1);
	}

	err = pthread_join(pth3,&tret);
	if(err)
		printf("can't join pthread consumer!\n");
	else
       		printf("pthread consumer exit with %d!\n",(int)tret);

	pthread_cancel(pth1);
	pthread_cancel(pth2);
	exit(0);
}

四、信号灯

1、定义

又叫做计数信号量,post一次信号量的值+1;wait一次,信号量的值-1,如果信号量的值已经为0,则wait将阻塞直至信号量的值>0;

2、相关函数

a.sem_init

函数原型:

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);

功能: 初始化信号量

参数: sem为要初始化的信号量地址

value为初始化设置的值

返回: X?

b.sem_destroy

函数原型:

int sem_destroy(sem_t * sem);

功能: 销毁信号量

参数: sem要销毁的信号量地址

返回: X?

c.sem_post

函数原型:

int sem_post(sem_t * sem);

功能: 信号量值+1

参数:

返回:

d.sem_wait

函数原型:

int sem_wait(sem_t * sem);

功能: 信号量值-1

参数: sem要销毁的信号量地址

返回: X?

e.sem_getvalue

函数原型:

int sem_getvalue(sem_t * sem);

功能: 获取信号量当前值

参数:

返回: X?

3、例程


五、文件读写锁

1、定义

2、相关函数

3、例程

推荐:linux多线程-----同步对象(互斥量、读写锁、条件变量)的属性

线程具有属性,同样用于线程同步的对象也有属性,主要有互斥量、读写锁和条件变量的属性。 互斥量属性: #include <pthread.h> int pthread_mutexattr_init(p

一、说明 linux的线程同步涉及: 1、互斥量 2、条件变量 3、信号灯 4、文件读写锁 信号灯很多时候被称为信号量,但个人仍觉得叫做信号灯比较好,因为可以与“SYSTEM V IPC的信号量”相区分(如

相关阅读排行


用户评论

游客

相关内容推荐

最新文章

×

×

请激活账号

为了能正常使用评论、编辑功能及以后陆续为用户提供的其他产品,请激活账号。

您的注册邮箱: 修改

重新发送激活邮件 进入我的邮箱

如果您没有收到激活邮件,请注意检查垃圾箱。