Linux多线程实现及线程同步函数分析

在Linux中,多线程的本质仍是进程,它与进程的区别:

进程:独立地址空间,拥有PCB

线程:也有PCB,但没有独立的地址空间(共享)

线程的特点:

1,线程是轻量级进程,有PCB,创建线程使用的底层函数和进程一样,都是clone

2,从内核看进程和线程是一样的,都有各自不同的PCB

3,进程可以蜕变成线程

4,在LINUX中,线程是最小的执行单位,进程是最小的分配资源单位

查看指定线程的LWP号命令:

ps -Lf pid

线程优点:

提高程序并发性

开销小

数据通信,共享数据方便

线程缺点:

库函数 ,不稳定

调试,编写困难,GDB

对信号支持不好

线程属性,可以在一开始就设置好分离态,具体在下面的代码有说明!

线程同步,主要有互斥锁mutex,读写锁,条件变量,信号量

线程创建函数原型:

int pthread_create(
    pthread_t *thread,  				// 线程ID
    const pthread_attr_t *attr, 		// 线程属性
    void *(*start_routine) (void *), 	// 线程主函数
    void *arg							// 主函数参数
);

  粘上基本创建线程模型:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>

//函数回调
void *mythread(void *args)
{
	printf("child thread id==[%ld]\n", pthread_self());
}

int main()
{
	pthread_t thread;

	//创建一个线程
	int ret = pthread_create(&thread, NULL, mythread, NULL);
	if(ret!=0)
	{
		printf("pthread_create error, [%s]\n", strerror(ret));
		return -1;
	}

	printf("main thread id==[%ld]\n", pthread_self());
	sleep(1);
}

  线程属性,在创建时分离代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>

void *mythread(void *args)
{
	printf("child thread id==[%ld]\n", pthread_self());
}

int main()
{
	pthread_t thread;
	//线程属性
	pthread_attr_t attr;

	//线程属性初始化
	pthread_attr_init(&attr);
	//设置线程到分离属性
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

	//创建一个线程
	int ret = pthread_create(&thread, &attr, mythread, NULL);
	if(ret!=0)
	{
		printf("pthread_create error, [%s]\n", strerror(ret));
		return -1;
	}

	printf("main thread id==[%ld]\n", pthread_self());
	sleep(1);

	ret = pthread_join(thread, NULL);
	if(ret!=0)
	{
		printf("pthread_join error, [%s]\n", strerror(ret));
	}

	//释放线程属性
	pthread_attr_destroy(&attr);

	return 0;
}

  互斥锁实现代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>

//定义一把锁
pthread_mutex_t mutex;

void *mythread1(void *args)
{
	while(1)
	{
		//加锁
		pthread_mutex_lock(&mutex);
		pthread_mutex_lock(&mutex);

		printf("hello ");
		sleep(rand()%3);
		printf("world\n");

		//解锁
		pthread_mutex_unlock(&mutex);
		sleep(rand()%3);
	}

	pthread_exit(NULL);
}

void *mythread2(void *args)
{
	while(1)
	{
		//加锁
		pthread_mutex_lock(&mutex);

		printf("HELLO ");
		sleep(rand()%3);
		printf("WORLD\n");

		//解锁
		pthread_mutex_unlock(&mutex);
		sleep(rand()%3);
	}

	pthread_exit(NULL);
}

int main()
{
	int ret;
	pthread_t thread1;
	pthread_t thread2;

	//随机数种子
	srand(time(NULL));

	//互斥锁初始化
	pthread_mutex_init(&mutex, NULL);

	ret = pthread_create(&thread1, NULL, mythread1, NULL);
	if(ret!=0)
	{
		printf("pthread_create error, [%s]\n", strerror(ret));
		return -1;
	}

	ret = pthread_create(&thread2, NULL, mythread2, NULL);
	if(ret!=0)
	{
		printf("pthread_create error, [%s]\n", strerror(ret));
		return -1;
	}

	//等待线程结束
	pthread_join(thread1, NULL);
	pthread_join(thread2, NULL);

	//释放互斥锁
	pthread_mutex_destroy(&mutex);
	return 0;
}

  读写锁代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>

int number = 0;

//定义一把读写锁
pthread_rwlock_t rwlock;

void *fun_write(void *args)
{
	int i = *(int *)args;
	int n;
	while(1)
	{
		//加写锁
		pthread_rwlock_wrlock(&rwlock);

		n = number;
		n++;
		//sleep(rand()%3);
		number = n;
		printf("W->[%d]:[%d]\n", i, number);

		//解写锁
		pthread_rwlock_unlock(&rwlock);
		sleep(rand()%3);
	}

	pthread_exit(NULL);
}

void *fun_read(void *args)
{
	int i = *(int *)args;
	while(1)
	{
		//加读锁
		pthread_rwlock_rdlock(&rwlock);

		printf("R->[%d]:[%d]\n", i, number);	

		//解锁
		pthread_rwlock_unlock(&rwlock);
		sleep(rand()%3);
	}

	pthread_exit(NULL);
}

int main()
{
	int i;
	int ret;
	int n = 8;
	int arr[8];
	pthread_t thread[8];

	//读写锁初始化
	pthread_rwlock_init(&rwlock, NULL);

	//创建3个写线程
	for(i=0; i<3; i++)
	{
		arr[i] = i;
		ret = pthread_create(&thread[i], NULL, fun_write, (void *)&arr[i]);
		if(ret!=0)
		{
			printf("pthread_create error, [%s]\n", strerror(ret));
			return -1;
		}
	}

	//创建5个读线程
	for(i=3; i<n; i++)
	{
		arr[i] = i;
		ret = pthread_create(&thread[i], NULL, fun_read, (void *)&arr[i]);
		if(ret!=0)
		{
			printf("pthread_create error, [%s]\n", strerror(ret));
			return -1;
		}
	}

	for(i=0; i<n; i++)
	{
		//回收子线程
		pthread_join(thread[i], NULL);
	}

	//释放读写锁资源
	pthread_rwlock_destroy(&rwlock);

	return 0;
}

  cond条件变量代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>

typedef struct node
{
	int data;
	struct node *next;
}NODE;

//链表头节点指针
NODE *head = NULL;

//互斥锁
pthread_mutex_t mutex;

//条件变量
pthread_cond_t cond;

//生产者线程处理函数
void *producer(void *args)
{
	NODE *pNode = NULL;	

	while(1)
	{
		pNode = (NODE *)malloc(sizeof(NODE));
		if(pNode==NULL)
		{
			perror("malloc error\n");
			exit(1);
		}
		pNode->data = rand()%1000;

		//lock共享资源
		pthread_mutex_lock(&mutex);

		pNode->next = head;
		head=pNode;
		printf("P:[%d]\n", head->data);

		//对共享资源解锁
		pthread_mutex_unlock(&mutex);

		//使用条件变量解除对线程到阻塞
		pthread_cond_signal(&cond);

		sleep(rand()%3);
	}
}

//消费者线程处理函数
void *consumer(void *args)
{
	NODE *pNode = NULL;
	while(1)
	{
		//lock共享资源
		pthread_mutex_lock(&mutex);

		if(head==NULL)
		{
			//条件不满足阻塞等待head不为空
			pthread_cond_wait(&cond, &mutex);
		}

		printf("C:[%d]\n", head->data);
		pNode = head;
		head = head->next;

		//对共享资源解锁
		pthread_mutex_unlock(&mutex);

		free(pNode);
		pNode = NULL;

		sleep(rand()%3);
	}
}

int main(int argc, char *argv[])
{
	int ret;
	pthread_t thread1;
	pthread_t thread2;
	pthread_mutex_t mutex;
	pthread_cond_t cond;

	//初始化互斥锁
	pthread_mutex_init(&mutex, NULL);

	//初始化条件变量
	pthread_cond_init(&cond, NULL);

	//创建生产者线程
	ret = pthread_create(&thread1, NULL, producer, NULL);
	if(ret!=0)
	{
		printf("pthread_create error, [%s]\n", strerror(ret));
		return -1;
	}

	//创建消费者线程
	ret = pthread_create(&thread2, NULL, consumer, NULL);
	if(ret!=0)
	{
		printf("pthread_create error, [%s]\n", strerror(ret));
		return -1;
	}

	//主线程回收子线程
	pthread_join(thread1, NULL);
	pthread_join(thread2, NULL);	

	//释放锁资源
	pthread_mutex_destroy(&mutex);

	//释放条件变量资源
	pthread_cond_destroy(&cond);

	return 0;
}

  信号量,经典消费者生产者模型:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

typedef struct node
{
	int data;
	struct node *next;
}NODE;

//链表头节点指针
NODE *head = NULL;

sem_t sem_consumer;
sem_t sem_producer;

//生产者线程处理函数
void *producer(void *args)
{
	NODE *pNode = NULL;	

	while(1)
	{
		pNode = (NODE *)malloc(sizeof(NODE));
		if(pNode==NULL)
		{
			perror("malloc error\n");
			exit(1);
		}
		pNode->data = rand()%1000;

		//sem_producer--, 若为0则阻塞
		sem_wait(&sem_producer);

		pNode->next = head;
		head=pNode;
		printf("P:[%d]\n", head->data);

		//sem_consumer++
		sem_post(&sem_consumer);

		sleep(rand()%3);
	}
}

//消费者线程处理函数
void *consumer(void *args)
{
	NODE *pNode = NULL;
	while(1)
	{
		//sem_consumer--, 若为0则阻塞
		sem_wait(&sem_consumer);

		printf("C:[%d]\n", head->data);
		pNode = head;
		head = head->next;

		//sem_producer++
		sem_post(&sem_producer);

		free(pNode);
		pNode = NULL;

		sleep(rand()%3);
	}
}

int main(int argc, char *argv[])
{
	int ret;
	pthread_t thread1;
	pthread_t thread2;

	//信号量初始化
	sem_init(&sem_producer, 0, 5);
	sem_init(&sem_consumer, 0, 0);

	//创建生产者线程
	ret = pthread_create(&thread1, NULL, producer, NULL);
	if(ret!=0)
	{
		printf("pthread_create error, [%s]\n", strerror(ret));
		return -1;
	}

	//创建消费者线程
	ret = pthread_create(&thread2, NULL, consumer, NULL);
	if(ret!=0)
	{
		printf("pthread_create error, [%s]\n", strerror(ret));
		return -1;
	}

	//主线程回收子线程
	pthread_join(thread1, NULL);
	pthread_join(thread2, NULL);	

	//释放信号量资源
	sem_destroy(&sem_producer);
	sem_destroy(&sem_consumer);

	return 0;
}

  

时间: 2024-10-12 19:19:53

Linux多线程实现及线程同步函数分析的相关文章

Linux程序设计学习笔记----多线程编程之线程同步之条件变量

转载请注明出处:http://blog.csdn.net/suool/article/details/38582521. 基本概念与原理 互斥锁能够解决资源的互斥访问,但是在某些情况下,互斥并不能解决问题,比如两个线程需 要互斥的处理各自的操作,但是一个线程的操作仅仅存在一种条件成立的情况下执行,一旦错过不可再重现,由于线程间相互争夺cpu资源,因此在条件成立的时候,该线程不一定争夺到cpu而错过,导致永远得不到执行..... 因此需要某个机制来解决此问题,更重要的是,线程仅仅只有一种情况需要执

Linux系统开发9 线程同步

[本文谢绝转载原文来自http://990487026.blog.51cto.com] <大纲> Linux系统编程8 线程同步 多线程共享资源,不加锁,同步互斥演示 多线程共享资源,加锁,同步互斥演示 读写锁:3个写线程,5个读线程,不加锁,并行处理 读写锁:3个写线程,5个读线程,加读写锁,串行处理 条件变量:生产消费者模型 信号量 进程间锁 文件锁: 习题 死锁,哲学家就餐 多线程共享资源,不加锁,同步互斥演示 [email protected]:~/linux_c/thread$ ca

Linux多线程程序设计------创建线程

1.创建线程 #include<pthread.h> int pthread_create(pthread_t* tidp,const pthread_attr_t *attr,void*(*start_rtn)(void),void*arg) tidp:线程id attr:线程属性(通常为空) start_rtn:线程要执行的函数 arg:start_rtn的参数 Linux多线程程序设计------创建线程,布布扣,bubuko.com

linux内核启动第二阶段之setup_arch()函数分析-2.6.36

执行setup_arch()函数 回到start_kernel当中,569行,调用setup_arch函数,传给他的参数是那个未被初始化的内部变量command_line.这个setup_arch()函数是start_kernel阶段最重要的一个函数,每个体系都有自己的setup_arch()函数,是体系结构相关的,具体编译哪个体系的setup_arch()函数,由顶层Makefile中的ARCH变量决定: 它首先通过检测出来的处理器类型进行处理器内核的初始化,然后通过 bootmem_init

.NET面试题解析(07)-多线程编程与线程同步

系列文章目录地址: .NET面试题解析(00)-开篇来谈谈面试 & 系列文章索引 关于线程的知识点其实是很多的,比如多线程编程.线程上下文.异步编程.线程同步构造.GUI的跨线程访问等等,本文只是从常见面试题的角度(也是开发过程中常用)去深入浅出线程相关的知识.如果想要系统的学习多线程,没有捷径的,也不要偷懒,还是去看专业书籍的比较好. 常见面试题目: 1. 描述线程与进程的区别? 2. 为什么GUI不支持跨线程访问控件?一般如何解决这个问题? 3. 简述后台线程和前台线程的区别? 4. 说说常

Linux多线程--使用互斥量同步线程【转】

本文转载自:http://blog.csdn.net/ljianhui/article/details/10875883 前文再续,书接上一回,在上一篇文章:Linux多线程——使用信号量同步线程中,我们留下了一个如何使用互斥量来进行线程同步的问题,本文将会给出互斥量的详细解说,并用一个互斥量解决上一篇文章中,要使用两个信号量才能解决的只有子线程结束了对输入的处理和统计后,主线程才能继续执行的问题. 一.什么是互斥量 互斥量是另一种用于多线程中的同步访问方法,它允许程序锁住某个对象,使得每次只能

Linux多线程实践(1) --线程理论

线程概念 在一个程序里的一个执行路线就叫做线程(thread).更准确的定义是:线程是"一个进程内部的控制序列/指令序列"; 一切进程至少有一个执行线程; 进程  VS. 线程  1.进程是资源分配(进程需要参与资源的竞争)的基本单位,而线程是处理器调度(程序执行)的最小单位; 2.线程共享进程数据,但也拥有自己的一部分(非常少O(∩_∩)O~)数据,如线程ID.程序计数器.一组寄存器.堆栈.errno(错误代码).信号状态.优先级等; 3.一个进程内部的线程可以共享资源,如代码段.数

java多线程二之线程同步的三种方法

java多线程的难点是在:处理多个线程同步与并发运行时线程间的通信问题.java在处理线程同步时,常用方法有: 1.synchronized关键字. 2.Lock显示加锁. 3.信号量Semaphore. 线程同步问题引入: 创建一个银行账户Account类,在创建并启动100个线程往同一个Account类实例里面添加一块钱.在没有使用上面三种方法的情况下: 代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

Delphi中线程类TThread实现多线程编程(线程同步技术、Synchronize、WaitFor……)

接着上文介绍TThread. 现在开始说明 Synchronize和WaitFor 但是在介绍这两个函数之前,需要先介绍另外两个线程同步技术:事件和临界区 事件(Event)与Delphi中的事件有所不同.从本质上讲,Event其实就相当于一个全局的布尔变量.它有两个赋值操作:Set和ReSet,相当于把它设置为 True或False.而检查它的值是通过WaitFor操作进行.对应在Windows平台上,是三个API函数:SetEvent.ResetEvent.WaitForSignalObje