code from <UNIX 高级编程第二版>
一个进程中的所有线程都可以访问该进程的组成部件,如文件描述符和内存。
pthread_t的数据类型表示线程ID
func1. pthread_t pthread_self(void)
返回线程ID
func2. int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict arg) 创建成功则返回0,否则返回错误编号
restrict,C语言中的一种类型限定符,用于告诉编译器,对象已经被指针所引用,不能通过除该指针外所有其他直接或间接的方式修改该对象的内容
第一个参数为指向线程标识符的指针
第二个参数用来设置线程属性
第三个参数是创建线程起始的运行函数
第四个参数是运行函数的参数
(void*)无类型指针,也可以认为是任意类型指针,其他任意类型的指针如int*等都可以转化成(void*)类型指针
单个线程的三种退出方式,在不终止整个进程的情况下停止它的控制流
(1)线程只是从启动例程中返回,返回值是线程的退出码
(2)线程可以被同一进程中的其他线程取消
(3)线程调用pthread_exit;
func3: void pthread_exit(void *rual_ptr)
参数rual_ptr与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join这个函数访问到这个指针
func4: int pthread _join(phread_t thread,void ** rual_ptr ) 若成功则返回0,否则返回错误编号
调用线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或者被取消。
获取已终止线程的退出码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* thr_fn1(void* arg)
{
printf("thread 1 return
");
return ((void*)1);
}
void* thr_fn2(void* arg)
{
printf("thread 2 exit
");
pthread_exit((void*)2);
}
int main()
{
pthread_t ntid1,ntid2;
int err;
void * tret;
err = pthread_create(&ntid1,NULL,thr_fn1,NULL);
if(err != 0)
{
printf("can not create thread 1
");
}
err = pthread_create(&ntid2,NULL,thr_fn2,NULL);
if(err != 0)
{
printf("can not create thread 2
");
}
err = pthread_join(ntid1,&tret);
if(err != 0)
{
printf("can not join thread 1");
}
printf("thread 1 exit code is %d
",(int)tret);
err = pthread_join(ntid2,&tret);
if(err != 0)
{
printf("can not join thread 2");
}
printf("thread 2 exit code is %d
",(int)tret);
exit(0);
}
func5: itn phread_cancel(pthread_t tid) 返回值为0则成功
线程可以通过调用上述函数来请求取消同一进程中的其他线程。但只是请求,不一定响应。
互斥量与线程同步
互斥量的本质是为了实现原子操作
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int tickets = 10;
pthread_mutex_t lock;
void* thread(void*arg)
{
while(tickets > 0)
{
//pthread_mutex_lock(&lock);
if(tickets > 0)
{
usleep (100*1000);
tickets --;
printf("%s sold tickets %d
",arg,tickets);
}
//pthread_mutex_unlock(&lock);
}
return (void*)1;
}
int main()
{
pthread_t tid1,tid2;
pthread_mutex_init(&lock,NULL);
int ret;
char*name = "the first :";
void* tret;
ret = pthread_create(&tid1,NULL,thread,(void*)name);
if(ret != 0)
{
printf("creat thread1 failed!
");
}
name = "the second :";
ret = pthread_create(&tid2,NULL,thread,(void*)name);
if(ret != 0)
{
printf("creat thread2 failed!
");
}
ret = pthread_join(tid1,&tret);
if(ret != 0)
{
printf("can not join thread 1");
}
ret = pthread_join(tid2,&tret);
if(ret != 0)
{
printf("can not join thread 2");
}
exit(0);
}
未加锁时结果如下:
加锁的结果:
未加锁时虽然ticket已经减到0了,但另一线程几乎同时走到了sleep的部分,于是再自减1得到-1的结果,加锁后则不会出现这样的情况,另一线程必须等到锁被unlock,才能继续走下去。