回顾:
线程 - 线程原理(CPU时间片)、线程的创建、线程的退出、线程参数和返回、线程同步-互斥量
线程的创建函数:
pthread_create(&id,0,线程函数指针,
线程函数的参数);
void* task(void*) - 线程函数的基本格式
在向task传参时,必须保证传入的指针有效。
返回值时,也要保证返回的指针有效。
线程创建以后,最好置成 分离状态或非分离状态:
pthread_detach() - 分离
pthread_join() - 非分离
线程退出两种方式:线程函数中使用return 或
pthread_exit(void*)
线程的同步:
因为线程使用的内存是共享进程的,因此有可能出现共享数据的冲突,解决方案就是 线程同步技术,核心理念:把并行访问改成串行访问。互斥量是线程同步技术的一种。互斥量的使用步骤:
1 声明 pthread_mutex_t lock;
2 初始化 两种方式: pthread_mutex_init() 或
声明的同时赋值:pthread_mutex_t lock =
PTHREAD_MUTEX_INITIALIZER;
3 加锁 pthread_mutex_lock()
4 读写
5 解锁 pthread_mutex_unlock();
6 确定不再使用,释放互斥量
pthread_mutex_destroy()
今天:
信号量 - 和signal无关,和信号量集无关。
死锁 - 同步技术 最忌讳
基于TCP的聊天室
信号量(semaphore)
信号量是一个计数器,用来控制访问临界资源的线程最大并行数量。当信号量的初始值为1时,效果等同于互斥量。
信号量不是最早的POSIX线程相关规范,因此信号量相关定义是在semaphore.h中。
semaphore.h中定义的信号量,既可以用于线程,又可以用于进程。
信号量的使用步骤:
1 定义信号量 sem_t sem;
2 初始化信号量 sem_init(&sem,0,计数初始值)
第二个参数为0,代表用于线程计数,其他值代表进程计数(进程计数目前Linux不支持)。
3 获取信号量(计数减1)
sem_wait(&sem);
4 读写资源
5 释放信号量(计数加1)
sem_post(&sem);
6 删除信号量 sem_destroy(&sem);
死锁
mutex m1,m2;
init(m1);init(m2);
启动两个线程A、B 同时运行;
A
lock(m1)
... <-- 运行到这个位置停止(时间片over)
lock(m2)<-- 运行到此阻塞,等待B线程释放m2
...
unlock(m2)
unlock(m1)
B
lock(m2)
... <-- 运行到此 没有问题
lock(m1) <-- 阻塞,等待A线程释放m1
...
unlock(m1)
unlock(m2)
多线程编程时,必须避免死锁 - 线程之间互相锁定叫死锁。避免死锁的经验:
顺序上锁,反向解锁,不要回调。
基于TCP的聊天室 - 自己一定要写
(参考TCPSERVER2)
基于TCP编写,一个聊天室最多100人
要求:
客户端:
1 用户需要登录,登录时只需要输入一个昵称即可
无需判断昵称是否重复(如果其他功能都OK考虑)
2 用户登录后连接服务器端,进入聊天室
3 用户可以输入聊天信息,也可以收到别人的聊天信息。
4 用户可以用 某个特殊单词 代表退出聊天室。
服务器端:
1 启动服务器,开放端口
2 等待客户端的连接,每连接上一个客户端,启动一个线程。
3 在线程中与客户端交互,交互过程:如果有客户端登陆、退出、提交聊天,都应该发给所有的客户端。需要保存所有客户端。
额外功能:可以考虑实现TCP的文件传输。