Linux线程及同步

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux线程及同步相关的知识,希望对你有一定的参考价值。

参考技术A linux多线程
1.线程概述
线程是一个进程内的基本调度单位,也可以称为轻量级进程。线程是在共享内存空间中并发的多道执行路径,它们共享一个进程的资源,如文件描述和信号处理。因此,大大减少了上下文切换的开销。一个进程可以有多个线程,也就
是有多个线程控制表及堆栈寄存器,但却共享一个用户地址空间。
2.线程实现
线程创建pthread_create()
所需头文件#include
<pthread.h>
函数原型int
pthread_create
((pthread_t
*thread,
pthread_attr_t
*attr,
thread:线程标识符
attr:线程属性设置
start_routine:线程函数的起始地址
arg:传递给start_routine的参数
函数返回值
成功:0
出错:-1
线程退出pthread_exit();
所需头文件#include
<pthread.h>
函数原型void
pthread_exit(void
*retval)
函数传入值retval:pthread_exit()调用者线程的返回值,可由其他函数如pthread_join
来检索获取
等待线程退出并释放资源pthread_join()
所需头文件#include
<pthread.h>
函数原型int
pthread_join
((pthread_t
th,
void
**thread_return))
函数传入值
th:等待线程的标识符
thread_return:用户定义的指针,用来存储被等待线程的返回值(不为NULL时)
函数返回值
成功:0
出错:-1
代码举例
1.
#include<pthread.h>
2.
#include<stdio.h>
3.
#include<errno.h>
4.
5.
/*线程1*/
6.
void
thread1()
7.

8.
int
i=0;
9.
10.
while(1)
11.

12.
printf(thread1:%d/n,i);
13.
if(i>3)
14.
pthread_exit(0);
15.
i++;
16.
sleep(1);
17.

18.

19.
20.
/*线程2*/
21.
void
thread2()
22.

23.
int
i=0;
24.
25.
while(1)
26.

27.
printf(thread2:%d/n,i);
28.
if(i>5)
29.
pthread_exit(0);
30.
i++;
31.
sleep(1);
32.

33.

34.
35.
int
main()
36.

37.
pthread_t
t1,t2;
38.
39.
/*创建线程*/
40.
pthread_create(&t1,NULL,(void
*)thread1,NULL);
41.
pthread_create(&t2,NULL,(void
*)thread2,NULL);
42.
/*等待线程退出*/
43.
pthread_join(t1,NULL);
44.
pthread_join(t2,NULL);
45.
return
0;
46.

3同步与互斥
<1>互斥锁
互斥锁的操作主要包括以下几个步骤。

互斥锁初始化:pthread_mutex_init

互斥锁上锁:pthread_mutex_lock

互斥锁判断上锁:pthread_mutex_trylock

互斥锁接锁:pthread_mutex_unlock

消除互斥锁:pthread_mutex_destroy
1.
#include<pthread.h>
2.
#include<stdio.h>
3.
#include<errno.h>
4.
5.
int
i=0;/*共享变量*/
6.
pthread_mutex_t
mutex=PTHREAD_MUTEX_INITIALIZER;/*互斥锁*/
7.
8.
void
thread1()
9.

10.
int
ret;
11.
while(1)
12.

13.
14.
15.
ret=pthread_mutex_trylock(&mutex);/*判断上锁*/
16.
17.
if(ret!=EBUSY)
18.

19.
pthread_mutex_lock(&mutex);/*上锁*/
20.
printf(This
is
thread1:%d/n,i);
21.
i++;
22.
pthread_mutex_unlock(&mutex);/*解锁*/
23.

24.
sleep(1);
25.

26.

27.
28.
void
thread2()
29.
int
ret;
30.
while(1)
31.

32.
33.
ret=pthread_mutex_trylock(&mutex);
34.
if(ret!=EBUSY)
35.

36.
pthread_mutex_lock(&mutex);
37.
printf(This
is
thread2:%d/n,i);
38.
i++;
39.
pthread_mutex_unlock(&mutex);
40.

41.
sleep(1);
42.

43.

44.
int
main()
45.

46.
pthread_t
t1,t2;
47.
pthread_mutex_init(&mutex,NULL);
48.
pthread_create(&t1,NULL,(void
*)thread1,NULL);
49.
pthread_create(&t2,NULL,(void
*)thread2,NULL);
50.
51.
pthread_join(t1,NULL);
52.
pthread_join(t2,NULL);
53.
54.
pthread_mutex_destroy(&mutex);
55.
return
0;
56.

<2>信号量
未进行同步处理的两个线程
1.
#include<pthread.h>
2.
#include<stdio.h>
3.
#include<errno.h>
4.
5.
int
i=0;
6.
void
thread1()
7.

8.
9.
while(1)
10.

11.
printf(This
is
thread1:%d/n,i);
12.
i++;
13.
sleep(1);
14.

15.

16.
17.
18.
void
thread2()
19.

20.
21.
while(1)
22.

23.
printf(This
is
thread2:%d/n,i);
24.
i++;
25.
sleep(1);
26.

27.

28.
29.
int
main()
30.

31.
pthread_t
t1,t2;
32.
33.
pthread_create(&t1,NULL,(void
*)thread1,NULL);
34.
pthread_create(&t2,NULL,(void
*)thread2,NULL);

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;
}

  

以上是关于Linux线程及同步的主要内容,如果未能解决你的问题,请参考以下文章

Mysql主从同步原理及配置-Linux

Mysql主从同步原理及配置-Linux

Mysql主从同步原理及配置-Linux

Mysql主从同步原理及配置-Linux

Mysql主从同步原理及配置-Linux

POSIX 多线程编程及理解