一、创建线程:
cpp
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void *threadrun(void *args) // 新线程
{
std::string name = (const char *)args;
while (true)
{
std::cout << "我是新线程 name: " << name << std::endl;
sleep(1);
}
return nullptr;
}
int main() // 函数向下执行创建新线程,新线程去执行threadrun,主线程继续向下执行
{
pthread_t tid; // 线程id
pthread_create(&tid, nullptr, threadrun, (void *)"thread-1"); // 线程id,线程属性为空,要执行的方法,参数
// 传进来字符串的起始地址就会交给要执行的方法
while (true) // 主线程
{
std::cout << "我是主线程..." << std::endl;
sleep(1);
}
return 0;
}
cpp
test_thread:TestThread.cc
g++ -o $@ $^ -lpthread
.PHONY:clean
clean:
rm -f test_thread
不是系统调用,需引入第三方库才可以运行
1.关于调度的时间片问题:
创建的时候时间片要等分,为了创建的线程不影响进程切换
2.一个线程异常,导致整个进程奔溃
二、引入pthread库:
Linux系统中不存在真正意义的线程,使用轻量级进程模拟的,OS中,只有轻量级进程,所谓模拟线程是我们的说法。但是用户只认线程,为了使用线程并且方便轻量级进程的封装,就有了pthread库,把创建轻量级进程的接口封装起来,给用户提供一批创建线程的接口。从此以后,用户用线程就用pthread库接口,底层的轻量级进程的概念不用关心。Linux的线程实现,是在用户层实现的,称之为用户级线程,pthread称为原生线程库。
主线程要等待新线程执行完不然会造成类似僵尸进程的问题,内存泄漏。
创建一个线程指定一个任务完成之后结果返回:
cpp
class Task
{
public:
Task(int a, int b) : _a(a), _b(b) {}
int Execute()
{
return (_a + _b);
}
~Task() {}
private:
int _a;
int _b;
};
class Result
{
public:
Result(int result) : _result(result)
{
}
int Getresult() { return _result; }
~Result() {}
private:
int _result;
};
void *routine(void *args)
{
Task *t = static_cast<Task *>(args);
sleep(1);
Result *res = new Result(t->Execute());
sleep(1);
return res;
}
int main()
{
pthread_t tid;
Task *t = new Task(10, 20);
int n = pthread_create(&tid, nullptr, routine, t);
// int cnt = 5;
// while(cnt--)
// {
// std::cout << "main线程名字: " << std::endl;
// sleep(1);
// }
Result *ret = nullptr;
pthread_join(tid, (void**)&ret); // 等待回收线程
int n = ret->Getresult();
std::cout << "新线程结束,运行结果: " << n << std::endl;
delete t;
delete ret;
return 0;
}
三、线程终止:
线程的入口函数,进行return就是线程终止。
线程不能用exit终止,因为exit是用来终止进程的。
pthread_exit终止调用线程
需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的, 不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
四、线程等待:
为什么需要线程等待?已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。创建新的线程不会复用刚才退出线程的地址空间。
调用该函数的线程将挂起等待,直到id为thread的线程终⽌。thread线程以不同的方法终止,通过 pthread_join得到的终止状态是不同的。
总结如下:1. 如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。 2. 如果thread线程被别的线程调用pthread_cancel异常终掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED。 3. 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。 4. 如果对thread线程的终⽌状态不感兴趣,可以传NULL给value_ptr参数。
cpp
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
void *routine(void *args)
{
std::string name = static_cast<const char *>(args);
int cnt = 10;
while (cnt--)
{
std::cout << "线程名字:" << name << std::endl;
sleep(1);
}
return (void *)10;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, routine, (void *)"thread-l");
int cnt = 5;
while (cnt--)
{
std::cout << "main线程名字:" << std::endl;
sleep(1);
}
void *ret = nullptr;
pthread_join(tid, &ret);
std::cout << "新线程结束,退出码:" << (long long)ret << std::endl;
return 0;
}

取消线程:主线程取消新线程,主线程是最后退的,因为要join,取消的时候要保证新线程已经启动。
线程被取消,推出结果为-1
五、线程分离:
默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
不想让线程被等待,想让新线程结束时就自己退出,就设置为分离状态,但被分离的线程依旧可以使用进程的资源。
分离的线程依旧在进程的地址空间中,进程的所有资源被分离的线程都可以访问,可以操作。
cpp
void *routine(void *args)
{
std::string name = static_cast<const char *>(args);
int cnt = 5;
while (cnt--)
{
std::cout << "main线程名字:" << name << std::endl;
sleep(1);
}
return nullptr;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, routine, (void *)"thread-l");
pthread_detach(tid);
std::cout << "新线程被分离" << std::endl;
int cnt = 5;
while (cnt--)
{
std::cout << "main线程名字:" << std::endl;
sleep(1);
}
int n = pthread_join(tid, nullptr);
if (n != 0)
{
std::cout << "pthread error" << std::endl;
}
else
{
std::cout << "pthread success" << std::endl;
}
return 0;
}
