`
kenby
  • 浏览: 724560 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

pthread线程的同步问题

阅读更多
1 互斥变量: pthread_mutex_t,本质上说是一把锁,在访问共享资源前对互斥量加锁,访问完成后释放锁。
   对互斥量进行加锁后,任何其他试图再次对互斥量加锁的线程将会被阻塞直至当前线程释放该互斥锁。
pthread_mutex_lock : 加锁
pthread_mutex_unlock:解锁

2 条件变量:pthread_cond_t,多个线程协作的一种同步方式,若某个条件不满足,线程将一直等待。条件变量一般
和互斥变量一起配合使用,因为条件变量本身是互斥访问的,所以要有一个互斥变量保护它。
pthread_cond_wait: 若条件不满组,一直等待下去
pthread_cond_signal: 把条件变量设为满足状态

3 实例: 两个线程,共同操作消息队列,线程1不断产生消息,添加到消息队列中,线程2不断处理消息队列中的消息
若消息队列为空,则等待直到有新的消息。写一个程序模拟此过程。
设置一个条件变量, pthread_cond_t    qready, 表示消息队列不为空
设置一个互斥变量, pthread_mutex_t  mutex, 用来保护qready和消息队列的互斥访问
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define SIZE 10000

typedef struct msg_t {
	int				data;
	struct msg_t 	*next;
} msg_t;

typedef struct global_t {
	msg_t 				*workq;
	pthread_cond_t 		qready;
	pthread_mutex_t		qlock;
	int					size;	/* 队列中待处理的消息数量 */
} global_t;

void *process_msg(void *arg)
{
	msg_t 		*mp;
	global_t	*global;
	int			done;

	global = (global_t *)arg;
	done = 0;
	while (done < SIZE) {
		pthread_mutex_lock(&global->qlock);
		while (global->size < 1) {
			printf("开始等待##############\n");
			pthread_cond_wait(&global->qready, &global->qlock);
			printf("等待结束##############\n");
		}
		mp = global->workq;
		global->workq = mp->next;
		global->size--;
		pthread_mutex_unlock(&global->qlock);
		printf("处理%d\n", mp->data);
		done++;
	}
	return (void *)0;
}

void enqueue_msg(global_t *global, msg_t *mp)
{
	pthread_mutex_lock(&global->qlock);
	mp->next = global->workq;
	global->workq = mp;
	global->size++;
	pthread_mutex_unlock(&global->qlock);
	pthread_cond_signal(&global->qready);
}

void *generate_msg(void *arg)
{
	int			i;
	global_t	*global;
	msg_t		*msg;

	global = (global_t *)arg;
	for (i = 0; i < SIZE; i++) {
		msg = malloc(sizeof(msg_t));
		msg->data = i;
		printf("%d入队...\n", i);
		enqueue_msg(global, msg);
		printf("%d入队完成...\n", i);
	}

	return (void *)0;
}

int main()
{
	pthread_t	ptid, gtid;
	global_t	global;
	void		*tret;

	global.workq = NULL;
	global.size = 0;

	pthread_cond_init(&global.qready, NULL);
	pthread_mutex_init(&global.qlock, NULL);

	pthread_create(&ptid, NULL, process_msg, &global);
	pthread_create(&gtid, NULL, generate_msg, &global);

	pthread_join(ptid, &tret);
	pthread_join(gtid, &tret);

	return 0;
}
 
上面的例子开启了两个线程分别用来产生和消耗消息,加上main,总共有3个线程在跑,如果把产生消息的工作放到
 main函数中,是否依然需要同步呢?当然需要,因为main函数本身也是一个线程,依然要和处理消息的线程保持同步。
 代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define SIZE 10000

typedef struct msg_t {
	int				data;
	struct msg_t 	*next;
} msg_t;

typedef struct global_t {
	msg_t 				*workq;
	pthread_cond_t 		qready;
	pthread_mutex_t		qlock;
	int					size;	/* 队列中待处理的消息数量 */
} global_t;

void *process_msg(void *arg)
{
	msg_t 		*mp;
	global_t	*global;
	int			done;

	global = (global_t *)arg;
	done = 0;
	while (done < SIZE) {
		pthread_mutex_lock(&global->qlock);
		while (global->size < 1) {
			printf("开始等待##############\n");
			pthread_cond_wait(&global->qready, &global->qlock);
			printf("等待结束##############\n");
		}
		mp = global->workq;
		global->workq = mp->next;
		global->size--;
		pthread_mutex_unlock(&global->qlock);
		printf("处理%d\n", mp->data);
		done++;
	}
	return (void *)0;
}

void enqueue_msg(global_t *global, msg_t *mp)
{
	pthread_mutex_lock(&global->qlock);
	mp->next = global->workq;
	global->workq = mp;
	global->size++;
	pthread_mutex_unlock(&global->qlock);
	pthread_cond_signal(&global->qready);
}

void *generate_msg(void *arg)
{
	int			i;
	global_t	*global;
	msg_t		*msg;

	global = (global_t *)arg;
	for (i = 0; i < SIZE; i++) {
		msg = malloc(sizeof(msg_t));
		msg->data = i;
		printf("%d入队...\n", i);
		enqueue_msg(global, msg);
		printf("%d入队完成...\n", i);
	}

	return (void *)0;
}

int main()
{
	pthread_t	ptid, gtid;
	global_t	global;
	void		*tret;

	global.workq = NULL;
	global.size = 0;

	pthread_cond_init(&global.qready, NULL);
	pthread_mutex_init(&global.qlock, NULL);

	pthread_create(&ptid, NULL, process_msg, &global);
	generate_msg(&global);		/* 把产生消息的工作放到main函数中 */

	pthread_join(ptid, &tret);

	return 0;
}
 
4 信号量 semaphore
mutex变量是非0即1的,可看作一种资源的可用数量,初始化时mutex是1,表示有一个可用资源,加锁
时获得该资源,将mutex减到0,表示不再有可用资源,解锁时释放该资源,将mutex重新加到1,表示又有了
一个可用资源。信号量(semaphore)和mutex类似,表示可用资源的数量,和mutex不同的是这个数量可以大于1。
这种信号量不仅可用于同一进程的线程间同步,也可用于不同进程间的同步。
linux中提供的接口为:
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_post(sem_t * sem);
int sem_destroy(sem_t * sem);
 
semaphore变量的类型为sem_t,sem_init()初始化一个semaphore变量,value参数表示可用资源的数量,
pshared参数为0表示信号量用于同一进程的线程间同步。在用完semaphore变量之后应该
调用sem_destroy()释放与semaphore相关的资源。
调用sem_wait()可以获得资源,使semaphore的值减1,如果调用sem_wait()时semaphore的值已经是0,
则挂起等待。如果不希望挂起等待,可以调用sem_trywait()。调用sem_post()可以释放资源,
使semaphore的值加1,同时唤醒挂起等待的线程。
semaphore实例:生产者和消费者问题
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>

#define NUM 5
int queue[NUM];
sem_t blank_number, product_number;

void *producer(void *arg) 
{
	int p = 0;
	while (1) {
		sem_wait(&blank_number);
		queue[p] = rand() % 1000 + 1;
		printf("Produce %d\n", queue[p]);
		sem_post(&product_number);
		p = (p+1)%NUM;
		sleep(rand()%5);
	}
}

void *consumer(void *arg) 
{
	int c = 0;
	while (1) {
		sem_wait(&product_number);
		printf("Consume %d\n", queue[c]);
		queue[c] = 0;
		sem_post(&blank_number);
		c = (c+1)%NUM;
		sleep(rand()%5);
	}
}

int main(int argc, char *argv[]) 
{
	pthread_t pid, cid;  

	sem_init(&blank_number, 0, NUM);
	sem_init(&product_number, 0, 0);
	pthread_create(&pid, NULL, producer, NULL);
	pthread_create(&cid, NULL, consumer, NULL);
	pthread_join(pid, NULL);
	pthread_join(cid, NULL);
	sem_destroy(&blank_number);
	sem_destroy(&product_number);
	return 0;
}
 
分享到:
评论

相关推荐

    pthread 线程标准 (中)

    5. **pthread_cond_wait()** 和 **pthread_cond_signal()**:条件变量的等待和信号操作,用于实现更复杂的线程同步策略。 #### pthread的高级特性 - **线程优先级与调度策略**:可以通过设置线程属性来调整线程的...

    由浅入深Linux下pthread线程库介绍

    Linux下的pthread线程库是实现多线程编程的关键工具,遵循POSIX标准,提供了一整套接口用于创建、管理线程以及同步线程间的操作。本文将深入探讨pthread线程库,包括线程的创建与结束、线程绑定、线程状态、线程...

    pthread线程库源代码

    在pthread线程库中,"锁的技巧"是一个重要的概念。锁是用来控制多个线程对共享资源访问的一种机制,以避免数据竞争和不一致性的发生。主要的锁类型包括: 1. 互斥锁(Mutex):互斥锁确保任何时候只有一个线程能...

    Pthread线程包 Windows移植版

    **Pthread线程包在Windows平台的移植与应用** Pthread,全称为POSIX线程,是UNIX系统标准的一部分,提供了跨平台的多线程编程接口。它在Linux和其他符合POSIX标准的操作系统中广泛使用,允许开发者创建并管理多个...

    Pthread多线程编程指南

    同时,了解线程同步和通信机制有助于预防和解决常见的并发问题,如死锁、饥饿和活锁。总之,《Pthread多线程编程指南》是提升多线程编程技能的宝贵资源,值得每一位关注性能优化和并发编程的开发者深入研究。

    c++pthread 线程封装

    总结来说,C++封装`pthread`线程涉及的关键点包括线程创建、线程函数、线程同步和线程管理。通过理解这些概念并结合实际应用,开发者可以在Linux环境中有效地利用多线程技术提高程序的并发性能。在实际项目中,还...

    pthread多线程求pi,linux多线程pthread,C,C++

    2. **线程同步**:在多线程环境中,数据一致性是个关键问题。`pthread_join()`函数用于等待特定线程的完成,确保线程间的正确顺序。另外,互斥锁(`pthread_mutex_t`)可用于保护共享资源,防止数据竞争。 3. **...

    linux pthread 多线程控制示例代码

    在实际应用中,还需要考虑线程安全、资源竞争、死锁等问题,以及如何正确地使用互斥锁`pthread_mutex_t`等同步工具来保护共享数据。多线程编程是一个复杂但强大的技术,能够帮助我们构建出更加灵活和高性能的应用...

    Jni多线程同步事例

    总结,"Jni多线程同步事例"着重展示了如何在JNI中应用线程同步技术解决生产者-消费者问题。理解并掌握这一技术有助于优化多线程Java应用,尤其是当需要调用本地库或实现高性能计算时。在实际项目中,应根据具体需求...

    Linux系统编程之线程同步

    线程同步,指一个线程发出某一功能调用时,在没有得到结果之前,该调用不返回。同时其它线程为保证数据一致性,不能调用该功能。 举例1: 银行存款 5000。柜台,折:取3000;提款机,卡:取 3000。剩余:2000 举例2...

    利用临界区的多线程同步测试.rar_临界区_多线程同步_线程 同步_线程同步

    "临界区"和"多线程同步"是解决这一问题的关键概念。临界区是一种同步机制,它允许一次只有一个线程访问特定的代码区域或资源,以避免并发访问时可能产生的数据竞争和不一致性。多线程同步则是为了协调多个线程的执行...

    pthread多线程c++动库下载

    使用pthread库可以编写出高效、并发的多线程程序,但需要注意线程安全问题,比如数据竞争和死锁。合理地使用锁(mutex)、信号量、条件变量等同步机制是至关重要的。同时,了解pthread的线程生命周期管理、线程局部...

    JNI 多线程同步机制的源码实现

    2. **多线程同步问题** 当多个Java线程调用同一个本地方法,它们可能同时访问和修改共享资源,这就需要同步控制。在Java中,我们可以使用`synchronized`关键字、`java.util.concurrent`包中的工具类等来实现同步。...

    操作系统实验报告——线程与进程同步

    实验内容集中在Linux下的多线程同步机制上,具体通过修改生产者-消费者问题的示例程序来实现。在这个问题中,多个生产者线程生成数据,而消费者线程负责消费这些数据。为了保证数据的一致性和正确性,需要防止多个...

    Pthread创建一个线程

    6. **线程同步与通信**:Pthread还提供了各种同步机制,如互斥锁(`pthread_mutex_t`)、条件变量(`pthread_cond_t`)、信号量(`sem_t`)等,用于控制线程间的执行顺序和数据共享安全。 7. **资源释放**:当线程...

    第2章-实验4-Pthread线程-yz1

    信号量(Semaphore)在Pthread中通过`semaphore.h`头文件进行操作,主要用于线程间的同步。`sem_init`用于初始化信号量,`sem_wait`会使信号量减一并可能阻塞线程,`sem_post`则使信号量加一,释放资源。`sem_...

    重大软院操作系统实验三:线程同步

    6. **哲学家就餐问题**:这是一个经典的线程同步问题,用来说明死锁的可能性。在实验中,你可以通过实现这个例子来理解线程同步的重要性,并学习如何避免死锁。 在"操作系统实验三"中,你可能需要编写代码来模拟...

    pthread多线程编程

    在计算机科学中,多线程编程是一种允许程序同时执行多个任务的技术。在Unix-like系统,如Linux,`pthread`库是实现多...然而,多线程编程也带来了复杂性和挑战,例如同步问题和资源管理,因此在实践中需要谨慎处理。

    线程同步 条件变量

    pthread 条件变量,线程同步

Global site tag (gtag.js) - Google Analytics