前言:
这两天又发生了不少的事情,真是诸事不顺,不过这些伤心的事由它去吧,自己的生活还要继续,自己定下来的目标也要去实现,所以没有时间再去伤心了。
1.为什么使用线程
1.使用多线程的必要性
传统的服务器使用为每一个客户调用一次fork,产生一个子进程的方式来处理客户连接,但是fork缺有不少的缺点:
a.fork调用昂贵,子进程需要复制父进程的内存,并且要复制所有的描述符。
b.fork之后子进程与父进程之间的通信很麻烦,需要使用IPC机制。
2.线程的优点
a.创建速度比进程快
b.同一个进程内的线程可以共享全局内存,但是需要解决同步问题。
2.线程基本函数
创建线程:
<span style="font-size:18px;">int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void*(*func)(void*), void *arg);</span>创建线程时只能传递一个参数过去,如果传递的是所需变量的地址,那么最好是给该变量开辟内存空间,然后将变量存在该空间中再传递过去。
等待线程终止:
<span style="font-size:18px;">int pthread_join(pthread_t *tid, void **status);</span>该函数不能像waitpid一样指定-1而等待任意一个线程。线程的返回值通过status参数返回。
获取线程id
<span style="font-size:18px;">pthread_t pthread_self(void);</span>脱离主线程:
int pthread_detach(pthread_t tid); 一般调用: pthread_detach(pthread_self());终止线程:
1.void phread_exit(void *status);
2.启动线程的函数可以返回,返回值是void指针。
3.进程退出。
3.线程特定数据
需要使用线程特定数据的理由是,由于同一个进程中的线程时共享全局变量的,那么如果使用了全局变量的函数在同一个进程的多个线程中使用,那么这个函数的是线程不安全的。一个线程未使用完成的值很有可能被另一个线程改写。
三个线程安全你的办法:
1.使用线程特定数据
2.改变函数,避免使用全局变量
线程特定数据的使用相对比较麻烦,不在这里详细叙述。
4.互斥锁
互斥锁是线程学习中最重要的部分,因为在多线程的使用中,最常用的模式就是各个线程对一个全局变量进行读写访问。因此保证该全局变量的原子操作使非常重要的。
使用方法:
<span style="font-size:18px;">int pthread_mutex_lock(pthread_mutex_t *mptr); int pthrea_mutex_unlock(pthread_mutex_t *mptr);</span>其中调用的指针便是互斥量。访问全局变量前锁定,访问完毕解锁。
5.条件变量
互斥锁适合于防止同时访问某个共享变量,但是我们需要另外某种在等待某个条件发生期间能让我们进入睡眠的东西。
需要一个让主循环进入睡眠,直到某个线程通知它有事可做才醒来的方法。条件变量结合互斥锁能够提供这个功能。互斥锁提供呼哧机制,条件变量提供信号机制。条件变量时类型为pthread_cond_t的变量。
int pthread_cond_wait(pthread_cond_t *cptr,pthread_mutex_t*mptr); int pthread_cond_signal(pthread_cond_t *cptr);条件变量需要配合一个互斥量使用,因为“条件”通常是指几个线程之间互相共享的一个变量,如果要测试该变量就必须保证测试时的原子操作,因此需要配合一个互斥量。
使用方法为,先锁住互斥量,然后测试全局变量是否符合条件,若不符合则调用wait函数。该函数将阻塞,并且释放互斥锁。当另外的线程修改全局变量,并且符合之前调用wait线程的条件时,那么发送signal,并且解锁互斥锁。然后wait函数返回,并且锁住互斥锁。此时就达到的等待条件的目的。
总结
线程必定是在多客户环境下最优的解决方案,并且随着越来越多的高并发编程的需求,这个方法必须要彻底的掌握才行。
其实线程的学习我已经在《linux程序设计》这部书中学习过一次。温故而知新,这一遍的复习让我更加的熟悉了多线程的编程。