《UNIX环境高级编程》读书笔记之线程(1)

1.线程标识

就像每个进程有一个进程ID一样,每个线程也都有一个线程ID。进程ID在整个系统中是唯一的,但线程ID不同,线程ID只在它所属的进程环境中有效。线程ID用pthread_t数据类型来表示,通过pthread_equal函数来比较两线程ID是否相同,通过pthread_equal函数可以得到当前线程的ID。


#include <pthread.h>

int pthread_equal(pthread_t tid1,pthread_t tid2);


#include <pthread.h>

pthread_t pthread_self(void);


2.线程的创建

新创建一个线程可以通过pthread_create函数来实现。

pthread_create函数原型:


pthread_create返回成功时,由tidp指向的内存单元被是指为新创建线程的ID,attr参数用来定制线程的各种不同属性。新线程从start_rtn函数的地址开始运行,该函数只有一个无类型指针参数arg。如果需要向函数传入多个参数,那么需要把这些参数放到结构体中,然后把这个结构体的地址作为arg参数传入。


3.进程终止

如果任一线程调用了exit,_Exit或者_exit,那么整个进程就会终止。类似的,如果信号默认的动作是终止进程,那么该信号发送到线程会终止整个进程。

以一下三种方式中的一种退出,可以在不终止整个进程的情况下停止它的控制流。

(1)线程只是从启动例程返回,返回值是线程的退出码。

(2)线程被同一进程中的其他线程取消。

(3)线程调用pthread_exit。

线程可以通过调用pthread_join函数等待同一进程中的其他线程结束。


调用pthread_join的线程将一直阻塞,知道等待的线程退出。


线程可以安排它退出时所要调用的函数,这与进程可以用atexit函数安排进程退出时要调用的函数类似。这与的函数称为线程清理函数。线程可以注册多个线程清理函数,它们执行的顺序与他们注册的顺序相反。


4.线程原语与进程原语之间的比较

我们发现,管理线程的系统调用与管理进程的系统调用有很多相似的地方。


有一点需要注意:在默认的情况下,线程的终止状态会被保存到对该线程调用pthread_join。如果线程之前通过pthread_detach已经处于分离状态,则线程的底层资源会在线程终止时立即被回收,此时不能通过pthread_join获得它的终止状态。


5.线程同步

互斥量(mutex)从本质上说是一把锁,在访问共享资源前对互斥量加锁,在访问完后释放互斥量。对互斥量加锁以后,任何其他试图再次对互斥量加锁的线程都会阻塞,直到加锁的线程释放该互斥锁。

互斥变量是用pthread_mutex_t数据类型表示的。再使用pthread_mutex_t数据类型之前,一定要对它进行初始化。可以把它设置为常量PTHREAD_MUTEX_INITIALIZER,也可以用pthread_mutex_init函数进程初始化。

如果要对互斥量加锁,需要调用pthread_mutex_lock,如果互斥量已经上锁,调用线程将阻塞直到互斥量被解锁。对互斥量解锁,需要调用pthread_mutex_unlock。如果不希望被阻塞,可以用pthread_nutex_trylock函数。


如果想避免永久阻塞的话,可以使用pthread_mutex_timedlock函数设置线程阻塞时间。但线程阻塞到超时时间时,pthread_mutex_timedlock函数返回错误码ETIMEDOUT。

#include <pthread.h>

#include <time.h>

int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,const struct timespec *restrict tsptr);

例子:

#include <stdio.h>
#include <pthread.h>
#include <time.h>

int main(void)
{
	int err;
	struct timespec tout;
	struct tm *tmp;
	char buf[64];
	pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

	pthread_mutex_lock(&lock);
	printf("mutex is locked\n");
	clock_gettime(CLOCK_REALTIME,&tout);
	tmp = localtime(&tout.tv_sec);
	strftime(buf,sizeof(buf),"%r",tmp);
	printf("the currrent time is %s\n",buf);
	tout.tv_sec += 10;
	err = pthread_mutex_timedlock(&lock,&tout);
	clock_gettime(CLOCK_REALTIME,&tout);
	tmp = localtime(&tout.tv_sec);
	strftime(buf,sizeof(buf),"%r",tmp);
	printf("the currrent time is %s\n",buf);
	return -1;
}

读写锁:读写锁与互斥量类似,不过读写锁允许更高的并行性。读写锁有三种状态:写模式下的加锁状态,读模式下的加锁状态,不加锁状态。一次只有一个线程可以占有写模式的读写锁,但是多个线程可以占有读模式的读写锁。

要在读模式下锁定读写锁,需要调用pthread_rwlock_rdlock。要在写模式下锁定读写锁,需要调用pthread_rwlock_wrlock。不管以何种方式锁住读写锁,都可以调用pthread_rwlock_unlock来解锁。


与互斥量类似,读写锁可以调用trylock来避免线程堵塞以及用timedlock来设定等待的时间。


屏障:屏障是用户协调多个进程并行工作的同步机制。屏障允许每个线程等待,直到所有合作线程都达到某一点,然后从改点继续执行。pthread_join函数就是一种屏障,允许一个线程等待,直到另外一个线程退出。

可以用pthread_barrier_init函数对屏障初始化,用pthread_barrier_destroy反初始化。

#include <pthread.h>

int pthread_barrier_init(pthread_barrier_t *restrict barrier,const pthread_barrierattr_t *restrict attr,unsigned int count);

其中count参数指定在允许所有线程运行下去之前,必须到达屏障的线程数目。使用attr参数指定屏障对象的属性。

使用pthread_barrier_wait的线程在屏障计数为满足条件时会进入休眠状态,直到满足屏障计数,所有的线程都被唤醒。

int pthread_barrier_wait(pthread barrier_t *barrier)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值