类unix系统中,早期是没有线程的概念的,80年代才引入,借助进程机制实现了线程的概念,因此在这类系统中,进程和线程关系密切。
线程号和线程ID的区别:线程号是cpu分配时间轮片的依据,线程ID是进程区分线程的依据
补充:MMU的工作过程,首先从PCB的三级页表指针找到页目录,然后通过页目录找到页表,通过页表找到物理单元。
优点:提高程序的并发性、开销小(相对进程)、共享数据方便
缺点:库函数不稳定、编写调试难不能用GDB、对信号支持不好
pthread_t pthread_self(void)
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg
char * strerror(int errnum)
来获取错误信息并输出#include
#include
#include
#include
#include
void * t_fun(void * arg) {
printf("In t_fun thread id = %lu, pid = %lu\n", (unsigned long)pthread_self(), (unsigned long)getpid());
return NULL;
}
int main(void) {
pthread_t tid;
printf("In t_fun thread id = %lu, pid = %lu\n", (unsigned long)pthread_self(), (unsigned long)getpid());
int ret = pthread_create(&tid, NULL, t_fun, NULL);
if(ret != 0) {
fprintf(stderr, "pthread_create failed: %s\n", strerror(ret));
exit(1);
}
sleep(1);
printf("In t_fun thread id = %lu, pid = %lu\n", (unsigned long)pthread_self(), (unsigned long)getpid());
return 0;
}
#include
#include
#include
#include
#include
void * t_fun(void * arg) {
long long int i = (long long int )arg;
sleep(i);
printf("%lldth thread id = %lu, pid = %lu\n", i, (unsigned long)pthread_self(), (unsigned long)getpid());
return NULL;
}
int main(void) {
pthread_t tid;
for(int i = 0; i < 5; i++) {
int ret = pthread_create(&tid, NULL, t_fun, (void *)i);
if(ret != 0) {
fprintf(stderr, "pthread_create failed: %s\n", strerror(ret));
exit(1);
}
}
sleep(5);
return 0;
}
线程之间共享全局变量:
#include
#include
#include
#include
#include
int var = 100;
int main(void) {
pthread_t tid;
printf("The first var = %d\n", var);
auto f = [](void *arg) mutable -> void* {var = 200; return NULL;};
int ret = pthread_create(&tid, NULL, f, NULL);
if(ret != 0) {
fprintf(stderr, "create failed: %s", strerror(ret));
exit(1);
}
sleep(1);
printf("after the var = %d\n", var);
return 0;
}
void pthread_exit(void *value_ptr);
阻塞线程退出,获取线程退出状态,对应进程的wait函数
int pthread_join(pthread_t thread, void ** value_ptr);
#include
#include
#include
#include
#include
#include
using std::shared_ptr;
using std::make_shared;
struct exit_t {
exit_t(char _c, int _val, char *_str) : c(_c), val(_val) {
strcpy(str, _str);
};
char c;
int val;
char str[200];
};
void *t_fun(void *arg) {
exit_t * exit_val = (exit_t *) arg;
exit_val->c = 'z';
exit_val->val = 200;
strcpy(exit_val->str, "zhang");
pthread_exit((void *)exit_val);
}
int main(void) {
//exit_t *exit_val = (exit_t*)malloc(sizeof(exit_t));
shared_ptr<exit_t> exit_val = make_shared<exit_t>(exit_t('f', 1000, "hahaha"));
pthread_t tid = 0;
int ret = pthread_create(&tid, NULL, t_fun, (void *)&exit_val);
if(ret != 0) {
printf("create error: %s\n", strerror(ret));
exit(1);
}
sleep(1);
pthread_join(tid, (void **) & exit_val);
printf("exit->c=%c, exit->val=%d, exit->str=%s\n", exit_val->c, exit_val->val, exit_val->str);
return 0;
}
将线程在状态层面上与主线程分离,常用于服务器编程和网络编程。
int pthread_detach(pthread_t tid);
#include
#include
#include
#include
#include
int main() {
auto f = [](void *arg) mutable -> void* {
int n = 3;
while(n--) {
printf("%d\n", n);
sleep(1);
}
pthread_exit((void *)1);
};
pthread_t tid = 0;
pthread_create(&tid, NULL, f, NULL);
pthread_detach(tid);
while(1) {
int ret = pthread_join(tid, NULL);
if(ret != 0) {
printf("error num: %d\n", ret);
printf("join error: %s\n", strerror(ret));
}
sleep(1);
}
return 0;;
}
用来杀死线程,但是有一定的延时性,需要到达固定的取消点(检查点)才能杀死线程。
pthread函数具有一定的延时性,比如玩游戏必须要到某个地方(客栈等)的存档点才能存档,在Linux中可以简单的认为系统函数中都会有一个cancel检查点,如果在函数体中没有检查点,那么需要手动调用pthread_testcancel函数来设置检查点发,但是有一定的延时性。
#include
#include
#include
#include
#include
int main(void) {
void *(*f)(void*arg) = [](void *arg) -> void*{
int i = 0;
while(1) {
printf("xxxlife: %d\n", i++);
//sleep(1);
pthread_testcancel();
}
};
pthread_t tid;
pthread_create(&tid, NULL, f, NULL);
sleep(3);
pthread_cancel(tid);
int ret = pthread_join(tid, NULL);
if(ret != 0) {
printf("join error: %s\n", strerror(ret));
}
return 0;
}
在目前的Linux系统中用处并不大,应为pthread_t为整型数据所以可以使用“==”来判断,但是在未来的Linux系统中可能会对pthread_t进行拓展。
int pthread_equal(pthread_t t1, pthread_t t2);
进程 | 线程 |
---|---|
fork | pthread_create |
exit | pthread_exit |
wait | pthread_join |
kill | pthread_cancel |
getpid | pthread_self |
无分离函数 | pthread_detach |
结构体原型:
typedef struct
{
int detachstate; 线程的分离状态
int schedpolicy; 线程调度策略
struct sched_param schedparam; 线程的调度参数
int inheritsched; 线程的继承性
int scope; 线程的作用域
size_t guardsize; 线程栈末尾的警戒缓冲区大小
int stackaddr_set;
void * stackaddr; 线程栈的位置
size_t stacksize; 线程栈的大小
}pthread_attr_t;
我们对于线程属性暂时掌握常用的三个属性:
int pthread_init(pthread_attr_t * attr);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int pthread_state)
THREAD_CREATE_DETACHED以及PTHREAD_CREATE_JOINABLE
#include
#include
#include
#include
#include
int main(void) {
auto f = [](void * arg) mutable -> void* {
printf("thread start");
pthread_exit((void*)1);
};
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_t tid;
int ret = pthread_create(&tid, &attr, f, NULL);
if(ret != 0) {
printf("create error: %s\n", strerror(ret));
exit(1);
}
ret = pthread_join(tid, NULL);
sleep(2);
if(ret != 0) {
printf("%d\n", ret);
printf("join error: %s\n", strerror(ret));
}
return 0;
}
用来设置线程栈的地址和大小
int pthread_attr_setstack(pthread_attr_t * attr, void * stack_addr, size_t stack_size);
#include
#include
#include
#include
#include
const int size = 0x10000000;
void * t_fun(void *arg) {
while(1) {
sleep(1);
}
pthread_exit((void *) 1);
}
int main(void) {
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
int detached;
pthread_attr_getdetachstate(&attr, &detached);
if(detached == PTHREAD_CREATE_DETACHED) {
puts("thread detached");
}
if(detached == PTHREAD_CREATE_JOINABLE) {
puts("thread joinable");
}
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
void * stackaddr = nullptr;
int cnt = 0;
while(1) {
stackaddr = malloc(size);
if(stackaddr == nullptr) {
perror("malloc");
exit(1);
}
pthread_attr_setstack(&attr, stackaddr, size);
int ret = pthread_create(&tid, &attr, t_fun, NULL);
if(ret != 0) {
printf("creat error: %s\n", strerror(ret));
printf("%d threads has create\n", cnt);
exit(1);
}
cnt++;
}
pthread_attr_destroy(&attr);
return 0;
}