linux网络编程----->线程死锁

开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件.

而出现数据混乱的原因:

    • 资源共享(独享资源则不会)
    • 调试随机(对数据的访问会出现竞争)
    • 线程间缺少必要的同步机制

以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱.

所以只能从第三点着手, 使多个线程在访问共享资源的时候, 出现互斥.

线程同步:

指在一定的时间里只允许某一个进程访问某个资源,而在此时间内,不允许其它线程对该资源进行操作.

在使用锁的时候, 以下会出现死锁状态.

    • 线程试图对一把锁进行加锁两次
    • 哲学家就餐[N个哲学家, N支筷子, 哲学家同时对一个方向取筷子, 取到后需要拿另一方面的场子才可以就餐]

线程试图对一把锁进行加锁两次:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
/*
 *   模拟一个线程对一把锁进行加锁两次
 *   author sea time 2016/06/15
 */

//创建一把互斥锁, 并进行静态初始化
pthread_mutex_t mutex =  PTHREAD_MUTEX_INITIALIZER;

//线程函数
void* thread_handler(void* args){
	//第一次获取锁成功
	pthread_mutex_lock(&mutex);
	//成功获取打印
	printf("get mutex 1 successfully!\n");
	//第二次获取同一把锁
	pthread_mutex_lock(&mutex);
	printf("get mutex 2 successfully!\n");
	pthread_mutex_unlock(&mutex);
	pthread_mutex_unlock(&mutex);

	pthread_exit(NULL);
}

int main(int argc, char* argv[]){
	pthread_t tid;
	pthread_create(&tid, NULL, thread_handler, NULL);

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

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

运行结果:

结果如预期所至, 一直阻塞在那获取锁.

哲学家就餐[N个哲学家, N支筷子, 哲学家同时对一个方向取筷子, 取到后需要拿另一方面的场子才可以就餐]:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
/*
 *	模拟哲学家用餐模型
 *  author sea time 2016/0615
 */
 //用五把锁模拟五支筷子
pthread_mutex_t mutex[5];

void* thread_handler(void* args){
	//获取当前位数
	long i = (long)args;
	int left, right;
	//当是最后一个哲学家
	if(sizeof(mutex)/sizeof(*mutex) == i + 1){
		left = i;
		right = 0;
	}
	else{
		left = i;
		right = i + 1;
	}
	//获取左边的筷子
	pthread_mutex_lock(&mutex[left]);
	//等待100毫秒, 让其它线程都拿到自己右边的筷子
	usleep(100);
	//获取右边的筷子
	pthread_mutex_lock(&mutex[right]);
	sleep(2);
	printf("%ld 吃完了....!\n", i);
	//解锁
	pthread_mutex_unlock(&mutex[right]);
	//解锁
	pthread_mutex_unlock(&mutex[left]);

	pthread_exit(NULL);
}
int main(int argc, char* argv[]){
	long i = 0;
	int ret = 0;
	pthread_t tid[5];

	//初始化五把锁
	for(i = 0; i < sizeof(mutex)/sizeof(*mutex); i++){
		pthread_mutex_init(mutex+i, NULL);
	}

	//创建五个线程
	for(i = 0; i < sizeof(tid)/sizeof(*tid); i++){
		pthread_create(tid+i, NULL, thread_handler, (void*)i);
	}

	//等待线程
	for(i = 0; i < sizeof(tid) / sizeof(*tid); i++){
		pthread_join(tid[i], NULL);
	}

	//释放五把锁
	for(i = 0; i < sizeof(mutex)/sizeof(*mutex); i++){
		pthread_mutex_destroy(mutex+i);
	}
	return ret;
}

运行结果: 会一直阻塞

结论: 在访问共享资源前加锁,访问结束后立即解锁。锁的“粒度”应越小越好。

时间: 2024-10-29 03:46:19

linux网络编程----->线程死锁的相关文章

linux网络编程-----&gt;线程同步一

开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 而出现数据混乱的原因: 资源共享(独享资源则不会) 调试随机(对数据的访问会出现竞争) 线程间缺少必要的同步机制 以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱. 所以只能从第三点着手, 使多个线程在访问共享资源的

linux网络编程-----&gt;线程同步--&gt;信号量

开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 而出现数据混乱的原因: 资源共享(独享资源则不会) 调试随机(对数据的访问会出现竞争) 线程间缺少必要的同步机制 以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱. 所以只能从第三点着手, 使多个线程在访问共享资源的

linux网络编程-----&gt;线程同步--&gt;条件变量

开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 而出现数据混乱的原因: 资源共享(独享资源则不会) 调试随机(对数据的访问会出现竞争) 线程间缺少必要的同步机制 以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱. 所以只能从第三点着手, 使多个线程在访问共享资源的

linux网络编程学习笔记之五 -----并发机制与线程?

进程线程分配方式 简述下常见的进程和线程分配方式:(好吧,我仅仅是举几个样例作为笔记...并发的水太深了,不敢妄谈...) 1.进程线程预分配 简言之,当I/O开销大于计算开销且并发量较大时,为了节省每次都要创建和销毁进程和线程的开销.能够在请求到达前预先进行分配. 2.进程线程延迟分配 预分配节省了处理时的负担,但操作系统管理这些进程线程也会带来一定的开销.由此,有个折中的方法是,当某个处理须要花费较长时间的时候,我们创建一个并发的进程或线程来处理该请求.实现也非常easy,在主线程中定时,定

linux网络编程学习笔记之五 -----并发机制与线程池

进程线程分配方式 简述下常见的进程和线程分配方式:(好吧,我只是举几个例子作为笔记...并发的水太深了,不敢妄谈...) 1.进程线程预分配 简言之,当I/O开销大于计算开销且并发量较大时,为了节省每次都要创建和销毁进程和线程的开销.可以在请求到达前预先进行分配. 2.进程线程延迟分配 预分配节省了处理时的负担,但操作系统管理这些进程线程也会带来一定的开销.由此,有个折中的方法是,当某个处理需要花费较长时间的时候,我们创建一个并发的进程或线程来处理该请求.实现也很简单,在主线程中定时,定时到期,

Linux网络编程

第二章 Linux网络编程 2.1客户——服务器模型 目前大多数网络应用程序在编写时都采用客户—服务器模型,假设一端是客户,另一端是服务器,让服务器提供给客户一定的服务内容.它要求有一方(服务器方)在启动执行程序后(无限期地)等待其他客户端程序与之通信.这里可以再分为两种具体类型:并发型交互与重复型交互. (1)并发型交互.在并发型交互模式下,程序的主要运作步骤如下: ·等待一个客户请求的到来: ·生成一个新的进程或者任务来处理这个客户请求,同时这里还可以接收其他客户的请求,处理结束后,终止这个

linux网络编程学习笔记之二 -----错误异常处理和各种碎碎(更新中)

errno 在unix系统中对大部分系统调用非正常返回时,通常返回值为-1,并设置全局变量errno(errno.h),如socket(), bind(), accept(), listen().erron存放一个正整数来保存上次出错的错误值. 对线程而言,每个线程都有专用的errno变量,不必考虑同步问题. strerror converts to English (Note: use strerror_r for thread safety) perror is simplified str

嵌入式 Linux网络编程(二)——TCP编程模型

嵌入式 Linux网络编程(二)--TCP编程模型 一.TCP编程模型 TCP编程的一般模型如下图: TCP编程模型分为客户端和服务器端编程,两者编程流程如下: TCP服务器端编程流程: A.创建套接字: B.绑定套接字: C.设置套接字为监听模式,进入被动接受连接状态: D.接受请求,建立连接: E.读写数据: F.终止连接. TCP客户端编程流程: A.创建套接字: B.与远程服务器建立连接: C.读写数据: D.终止连接. 二.TCP迭代服务器编程模型 TCP循环服务器接受一个客户端的连接

linux网络编程学习笔记之六 -----I/O多路复用服务端

多进程和多线程的目的是在于最大限度地利用CPU资源,当某个进程不需要占用太多CPU资源,而是需要I/O资源时,可以采用I/O多路复用,基本思路是让内核把进程挂起,直到有I/O事件发生时,再把控制返回给程序.这种事件驱动模型的高效之处在于,省去了进程和线程上下文切换的开销.整个程序运行在单一的进程上下文中,所有的逻辑流共享整个进程的地址空间.缺点是,编码复杂,而且随着每个逻辑流并发粒度的减小,编码复杂度会继续上升. I/O多路复用典型应用场合(摘自UNP6.1) select的模型就是这样一个实现