jsp做网站下载图片,wordpress皮肤下载站,公司网站架构,wordpress在线版本目录
一、线程创建
1.1 pthread_create
1.2 线程传入启动函数参数方式
二、线程退出(pthread_exit函数 pthread_cancel函数)
三、线程等待
3.1 为什么要线程等待#xff1f;
3.2 pthread_join函数 四、线程分离
4.1 pthread_detach() 和 pthread_self()
五、pthread库…目录
一、线程创建
1.1 pthread_create
1.2 线程传入启动函数参数方式
二、线程退出(pthread_exit函数 pthread_cancel函数)
三、线程等待
3.1 为什么要线程等待
3.2 pthread_join函数 四、线程分离
4.1 pthread_detach() 和 pthread_self()
五、pthread库维护线程的基本结构 一、线程创建
1.1 pthread_create thread:返回线程ID attr:设置线程的属性attr为NULL表示使用默认属性start_routine:是个函数地址线程启动后要执行的函数arg:传给线程启动函数的参数 返回值成功返回0失败返回错误码 1.2 线程传入启动函数参数方式
关于第四个参数我们要注意其是void*类型指针任意指针都可以传给线程现在我们模拟一种错误的传参方式传栈区资源基于线程运行顺序产生的传参问题
#define NUM 5
void* pthread_route(void* args)
{const char* name (const char*)args;cout new thread create success, its name: nameendl;
}int main()
{pthread_t pid;for(int i0;iNUM;i){char buffer[64];snprintf(buffer,sizeof(buffer),thread %d,i1);pthread_create(pid,nullptr,pthread_route,buffer);}sleep(1);return 0;
}
运行结果 结果显示我们的线程名字都是一样的 首先我们可以知道这样的结果说明我们传过去的buffer地址是同一个地址 有人可能疑惑不是每次循环后buffer的地址应该每次不一样吗 这里结合函数栈帧知识发现并没有函数调用所以每次都还是在main函数栈帧内所以每次的地址其实循环进来依旧是原来的地址 有人又会提出不对啊按道理应该数字是根据i1的来啊按照我们route函数思路不应该全是5啊 这就说明事实不是按照我们的所想main函数创建线程后并不是立马执行线程对应的函数当main函数创建完所有线程后才执行线程的代码而此时配合前面buffer首地址没变而里面的数据再不断变换导致 所以我们创建线程如果想看到线程私有的东西不能传入共享的数据我们不能传入栈内资源(这里没有多想其他场景)所以我们应该利用堆区资源 正确的传参方式数据放入堆区传堆区指针
#include iostream
#include pthread.h
#include string
#include unistd.h
#define NUM 3
using namespace std;//每个线程独立的资源 线程ID 线程buffer
class Thread_data
{
public:pthread_t _pid;char namebuffer[64];
};void *thread_route(void *args)
{Thread_data *p static_castThread_data *(args);int cnt 3;while (cnt--){cout new thread create success,its name: p-namebuffer cnt: cnt cnt cntendl;}delete p;return nullptr;
}int main()
{for (int i 0; i NUM; i){Thread_data *pt new Thread_data();snprintf(pt-namebuffer, sizeof(pt-namebuffer), thread %d, i 1);pthread_create(pt-_pid, nullptr, thread_route, pt);}sleep(1);return 0;
}
运行结果 二、线程退出(pthread_exit函数 pthread_cancel函数) void pthread_exit(void *value_ptr); 参数 value_ptr:value_ptr不要指向一个局部变量。 返回值无返回值跟进程一样线程结束的时候无法返回到它的调用者自身 pthread_cancel 功能取消一个执行中的线程 int pthread_cancel(pthread_t thread); 参数 thread:线程ID 返回值成功返回0失败返回错误码 三、线程等待
3.1 为什么要线程等待
为什么要有线程等待回想以前的进程等待父进程回收子进程获取子进程退出信息
对于已经退出的线程其空间没有被释放仍在进程的地址空间内所以创造新的线程不会复用刚才退出线程的地址空间这就造成了资源的浪费
3.2 pthread_join函数 原型 int pthread_join(pthread_t thread, void **value_ptr); 参数 thread:线程ID value_ptr:它指向一个指针后者指向线程的返回值 返回值成功返回0失败返回错误码 线程的调用逻辑函数返回值是void*该函数会在线程结束前将线程结束状态码保存进pthread库中打个比方它的数字状态码是10然后通过强转(void*)10将4字节整形放入8字节的指针中(Linux下指针默认是64位下)。外部获取函数内部结果我们需要传地址所以要传void**
需要知道的是我们返回的值一定是右值也就输说常变量、堆空间资源可以返回栈上数据不能返回因为函数栈帧结束后栈空间数据会被销毁
#includeiostream
#includeunistd.h
#includepthread.h
#includevectorusing namespace std;
#define NUM 5
class pthread_data
{
public:pthread_t tid;char buffer[128];
};
class Thread_ret
{
public:int exit_code;int exit_result;
};void* pthread_route(void* args)
{Thread_ret* ret new Thread_ret();int cnt 5;while(cnt){cout cnt: cnt-- cnt: cntendl;//BUG?sleep(1);}ret-exit_code 106;ret-exit_result 0;return (void*)ret;
}
int main()
{vectorpthread_data* vp;for(int i0;iNUM;i){pthread_data* pd new pthread_data();pthread_create(pd-tid,nullptr,pthread_route,pd);snprintf(pd-buffer,sizeof(pd-buffer),thread :%d pid:0x%x ,i1,pd-tid);vp.push_back(pd);}for(auto e : vp){cout creat thread success: e-bufferendl;}for(autoe :vp){Thread_ret* ret;pthread_join(e-tid,(void**)(ret));cout join : e-buffer success exit code: ret-exit_code exit result: ret-exit_resultendl;delete e;}cout main quit!endl;return 0;
} 四、线程分离
1.默认情况下新创建的线程是joinable的线程退出后需要对其进行pthread_join操作否则无法释放资源从而造成系统泄漏。 2.如果不关心线程的返回值join是一种负担这个时候我们可以告诉系统当线程退出时自动释放线程资源。
4.1 pthread_detach() 和 pthread_self()
分离线程可以是指定的其他线程也可以是自己
int pthread_detach(pthread_t thread);
pthread_self()获取线程自己的ID 五、pthread库维护线程的基本结构
在前面我们了解到线程有属于自己的ID、私有栈等等结构这些线程肯定需要被组织如何组织呢在Linux下线程库内用结构体(TCP)对每个线程进行组织库其实本质是磁盘上的文件在链接的时候将内容加载到内存的共享区内也就是说我们的线程的属性存储在共享区内线程的私有栈区实在共享区内 线程的局部存储可以使一个全局变量让所有线程私有栈内创建一份
在全局变量前面加上__thread 即可