多线程编程同步问题(C、Linux)

下面我们要讨论多线程编程环境下用于线程同步的方式,有:POSIX信号量、互斥量、条件变量。

POSIX信号量

POSIX信号量函数有五个如下:

#include<semaphore.h>

int sem_init(sem* sem, int pshared, unsigned int value);
int sem_destroy(sem_t* sem);
int sem_wait(sem_t* sem);
int sem_trywait(sem_t* sem);
int sem_post(sem_t* sem);

sem_int函数用于初始化一个信号量(POSIX支持有名信号量,这里不讨论),pshared如果是0就表示这个信号量是当前进程的局部信号量(其他值的话用于进程共享,不讨论),value指定信号量的初始值。一定要注意不要初始化一个已经初始化的信号量

sem_desroty函数用于释放信号量,一定要注意不要去destroy一个正在被占用的信号量。

sem_wait将信号量的value减1,如果value是0,sem_wait将被阻塞,直到这个信号量的值非0。

sem_trywait与sem_wait相似,只是它不阻塞,无论value是否是非零,他都返回。如果value是0,他会返回-1并设置errno为EAGAIN。

sem_post函数将信号量加1,当然这个操作是原子操作,如果信号量的值大于0,其他被sem_wait等待的线程将被唤醒。

互斥锁

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* mutexattr);
int pthread_mutex_destroy(pthread_mutex_t* mutex);
int pthread_mutex_lock(pthread_mutex_t* mutex);
int pthread_mutex_unlock(pthread_mutex_t* mutex);
int pthread_mutex_trylock(pthread_mutex_t* mutex);

pthread_mutex_t是一个结构体类型,pthread_mutexattr_t结构体定义的是互斥锁属性(如果设置为NULL就是默认属性)。

init函数用来初始化互斥锁,destory函数用来销毁锁(当然得注意不要销毁一个正在被占用的互斥锁),

lock加锁,unlock解锁,当然trylock是非阻塞版本,失败就会返回错误码。

条件变量

#include <pthread.h>

int pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* cond_attr);
int pthread_cond_destroy(pthread_cond_t* cond);
int pthread_cond_broadcast(pthread_cond_t* cond);
int pthread_cond_signal(pthread_cond_t* cond);
int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex);

init函数用于初始化一个条件变量,如果cond_attr是NULL,那么就按默认属性初始化

destroy销毁条件变量,如果条件变量正在被使用则返回EBUSY错误码(和前两个不同).

broadcast唤醒所有等待的线程,signal唤醒一个,至于是哪一个取决于线程的优先级和调度策略.

wait函数调用前一定要确保 mutex上锁,wait函数的调用会先将调用线程放入条件变量的等待队列中,然后将互斥量解锁.显然wait函数执行将调用线程放入条件变量的等待队列中这个过程, signal,broadcast函数不会修改条件变量,换一句话说就是wait函数不会错过条件变量的任何变化. wait函数返回成功后mutex会被继续上锁.

生产者消费者模型

下面是关于条件变量的测试代码,条件变量结合互斥锁经常被用到生产者和消费者模型中,

这里要注意的是条件变量最好放在while里面,下面例子可以用if代替.至于为什么放在while里面比较好,读者可以自己研究.

#include <pthread.h>
#include <list>
#include <stdio.h>
#include <unistd.h>
using namespace std;

pthread_mutex_t list_mutex = PTHREAD_MUTEX_INITIALIZER;//静态初始化
pthread_cond_t cond_em = PTHREAD_COND_INITIALIZER;

list<long> my_list;
void* consume(void* arg)
{
	while(1)
	{
		pthread_mutex_lock(&list_mutex);
		while(my_list.empty())
		{
			pthread_cond_wait(&cond_em, &list_mutex);
		}
		printf("value = %d\n", my_list.back());
		my_list.pop_back();
		pthread_mutex_unlock(&list_mutex);
		sleep(1);
	}
	
}

void* produce(void* arg)
{
	long temp = (long)arg;
	while(1)
	{
		pthread_mutex_lock(&list_mutex);
		my_list.push_back(temp);
		pthread_mutex_unlock(&list_mutex);
		pthread_cond_signal(&cond_em);
		sleep(1);
	}
}


int main()
{
	int i = 0;
	pthread_t* pid = new pthread_t[10];
	for(; i < 5; ++i)
	{
		pthread_create(pid+i, NULL, &produce, (void*)i);
	}
	for(; i < 10; ++i)
	{
		pthread_create(pid+i, NULL, &consume, (void*)i);
	}
	--i;
	sleep(10);
	for(; i>=0; --i)
	{
		pthread_join(pid[i], NULL);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值