1、多个进程使用操作系统提供的复杂机制才能实现内存和文件描述符的共享。每个线程都包含有表示执行环境所必须的信息,其中包括进程中标志线程的线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno变量以及线程私有数据。一个进程的所有信息对该进程的所有线程都是共享的,包括执行程序的代码、程序的全局内存和堆内存、栈以及文件描述符。
2、线程ID只有在它所属的进程上下文中才有意义。Linux使用无符号长整形表示pthread_t数据类型,其他用结构指针表示。
#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
pthread_t pthread_self(void);
3、线程创建
程序运行时,以进程中单个控制线程启动。线程的创建并不保证哪个线程会先运行,新线程继承调用线程的浮点环境和信号屏蔽字,但是该线程的挂起信号集会被清除。
由于pthread库不是Linux系统默认的库,在gcc编译的使用应该加上 -pthread 选项 如: gcc -o 1.out -pthread 1.c
//成功返回0,否则返回出错码,每个线程都提供errno的副本
//创建产生的tid通过tidp返回
//如果需要向star_rtn函数传递一个以上参数,则把这些参数放在一个结构体中,把结构体地址作为arg参数传入
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*star_rtn)(void *), void *restrict arg);
主线程需要休眠,如果主线程不休眠,它就可能会退出,这样新线程还没有机会运行,整个进程可能就已经终止了。不过Linux中新创建的线程先运行。
#include "apue.h"
#include <pthread.h>
pthread_t ntid;
void printids(const char *s)
{
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %lu tid %lu (0x%lx)\n",s,(unsigned long)pid,(unsigned long)tid,(unsigned long)tid);
}
void *thr_fn(void *arg)
{
printids("new threadL");
return ((void *)0);
}
int main(void)
{
int err;
err = pthread_create(&ntid, NULL, thr_fn, NULL);
if(err != 0)
err_exit(err, "can't create thread");
printids("main thread:");
sleep(1);
exit(0);
}
4、线程终止
单线程可以通过3种方式退出(不退出进程)
(1)从启动例程中返回
(2)被其他线程取消
(3)调用pthread_exit
void pthread_exit(void *rval_ptr);
//pthread_join可以访问pthread_exit传递的rval_ptr
//调用线程一直阻塞,直到直到线程调用pthread_exit,或返回,或取消
int pthread_join(pthread_t thread, void **rval_ptr);
#include "apue.h"
#include <pthread.h>
//return 和pthread_exit传递的参数都会给pthread_join中第二个参数
void *thr_fn1(void *arg)
{
printf("thread 1 returning\n");
return ((void *)1);
}
void *thr_fn2(void *arg)
{
printf("thread 2 exiting\n");
pthread_exit((void *)2);
}
int main(void)
{
int err;
pthread_t tid1, tid2;
void *tret;
err = pthread_create(&tid1, NULL, thr_fn1, NULL);
err = pthread_create(&tid2, NULL, thr_fn2, NULL);
err = pthread_join(tid1,&tret);
printf("thread 1 exit code %ld\n", (long)tret);
err = pthread_join(tid2,&tret);
printf("thread 2 exit code %ld\n", (long)tret);
exit(0);
}
5、
//请求某一线程终止
int pthread_cancel(pthread_t tid);
//下面两个函数成对出现,如果异常退出则之间会执行rtn清理函数,参数arg会传递给具体函数
//如果正常退出则不执行清理函数
//注册的清理函数存在栈中,先进后出
void pthread_cleanup_push(void (*rtn)(void *), void *arg);
void pthread_cleanup_pop(int execute);
//分离线程,一般线程的终止状态会保存到对该线程调用pthread_join,分离后就不可以调用
int pthread_detach(pthread_t tid);
6、互斥量
//表示互斥量以静态数据表示
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
//动态创建一个互斥量(malloc和free),在这之间操作互斥量(上锁,解锁)
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutex_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
7、死锁
线程试图对同一互斥量加锁两次,那么它自身就会陷入死锁状态。使用两个以上互斥量时,线程会存在互锁的情况。