pthread_join 函数用于实现线程等待。其中的 retval 参数用于传递目标线程的退出状态。当目标线程结束时,pthread_join 会将目标线程的退出状态(即线程函数的返回值或通过 pthread_exit 传递的参数)存储在 *retval 所指向的内存位置上。换句话说,pthread_join 会修改 retval 所指向的 void * 类型变量的值。
以下是相关的代码示例:
#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;
int g_val = 100;
void *threadRoutine(void *args) {
const char *name = (const char *)args;
int cnt = 5;
while (true) {
printf("%s, pid: %d, g_val: %d, &g_val: 0X%p\n", name, getpid(), g_val, &g_val);
sleep(1);
cnt--;
if (cnt == 0)
break;
}
pthread_exit((void *)100);
}
int main() {
pthread_t pid;
pthread_create(&pid, nullptr, threadRoutine, (void *)"Thread 1");
void *ret;
pthread_join(pid, &ret);
cout << "Thread returned: " << (long long int)ret << endl;
return 0;
}
通过上面的代码和图片,我们可以看到,新线程的输出参数可以被主线程获取,并且全局变量可以被所有线程访问,是共享资源,因此全局函数也可以被所有线程访问。
&ret 接收退出状态的具体过程如下:当调用 pthread_join 时,pthread_join 会阻塞当前线程,直到由 thread 参数指定的目标线程终止。一旦目标线程终止,pthread_join 会将该线程调用 pthread_exit 时传递的 void* 指针(即退出状态)赋值给 &ret 所指向的 void* 变量,即 ret。pthread_join 成功完成等待和状态获取后,会返回 0,表示操作成功,当前线程可以继续执行后续代码。
全局变量是被所有线程共享的。如果我们的线程需要有自己的私有数据,即只能自己访问而其他线程不能访问,我们可以在全局变量前加上关键字 __thread 来修饰,这是编译器为我们提供的只能用来修饰内置类型的关键字。
以下是相关的代码示例:
#include <iostream>
#include <pthread.h>
#include <vector>
#include <string>
#include <unistd.h>
using namespace std;
#define NUM 3
int *p = nullptr;
__thread int val = 100;
class ThreadInfo {
public:
ThreadInfo(const string &threadname) : threadname_(threadname) {}
public:
string threadname_;
};
string toHex(pthread_t tid) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "%p", tid);
return buffer;
}
void *threadroutine(void *args) {
int i = 0;
ThreadInfo *ti = static_cast<ThreadInfo*>(args);
while(i < 5) {
printf("%s, tid: %s, pid: %d, val: %d, &val: 0X%p\n", ti->threadname_.c_str(), toHex(pthread_self()).c_str(), getpid(), val, &val);
val++;
i++;
sleep(1);
}
return nullptr;
}
int main() {
vector<pthread_t> tids;
vector<ThreadInfo> thread_datas;
for(int i = 0; i < NUM; i++) {
thread_datas.emplace_back("Thread-" + to_string(i + 1));
pthread_t tid;
pthread_create(&tid, nullptr, threadroutine, &thread_datas.back());
tids.push_back(tid);
}
for(auto tid : tids) {
pthread_join(tid, nullptr);
}
return 0;
}
通过观察我们可以发现,在相同线程的情况下,val 的值是递增的,但对于不同的线程之间,val 值是没有关系的。因此,我们通过关键字 __thread 实现了线程的局部存储,这些属于每个线程的 val 的地址在线程的独立栈中。
互斥的概念
在大部分情况下,线程使用的数据都是局部变量,变量的地址空间在线程栈空间内,这种情况下,变量属于单个线程,其他线程无法获得这个变量。但有时候,很多变量需要在线程之间共享,这些变量被称为共享变量,可以通过数据的共享,完成线程之间的交互。
需要互斥的原因
10分钟内自己学会PHP其中,第1篇为入门篇,主要包括了解PHP、PHP开发环境搭建、PHP开发基础、PHP流程控制语句、函数、字符串操作、正则表达式、PHP数组、PHP与Web页面交互、日期和时间等内容;第2篇为提高篇,主要包括MySQL数据库设计、PHP操作MySQL数据库、Cookie和Session、图形图像处理技术、文件和目录处理技术、面向对象、PDO数据库抽象层、程序调试与错误处理、A
524
在各个线程访问共享变量的时候,会出现多进程并发的操作,可能会带来一些问题。
下面是一个经典的抢票问题,每个线程访问到共享资源的票数就给它减一,就相当于是抢走一张票。
以下是相关的代码示例:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <unistd.h>
#include <pthread.h>
using namespace std;
#define NUM 4
class threadData {
public:
threadData(int number) {
threadname = "thread-" + to_string(number);
}
public:
string threadname;
};
int tickets = 1000;
void *getTicket(void *args) {
threadData *td = static_cast<threadData*>(args);
const char *name = td->threadname.c_str();
while (true) {
if(tickets > 0) {
usleep(1000);
printf("who=%s, get a ticket: %d\n", name, tickets);
tickets--;
}
else
break;
}
printf("%s ... quit\n", name);
return nullptr;
}
int main() {
vector<pthread_t> tids;
vector<threadData> thread_datas;
for (int i = 1; i <= NUM; i++) {
thread_datas.emplace_back(i);
pthread_t tid;
pthread_create(&tid, nullptr, getTicket, &thread_datas.back());
tids.push_back(tid);
}
for(auto tid : tids) {
pthread_join(tid, nullptr);
}
return 0;
}我们将程序执行两遍:
第一遍:

第二遍:

我们发现,抢票怎么还能抢出第0票呢,甚至还有-1、-2票?而且竟然还有抢到一张票的情况,下面我们来详解一下。
首先,如果我们只讨论一个线程,整个抢票的过程就是,ticket 在内存中,线程读取 ticket,然后线程把 ticket 变量放到 CPU 上,CPU 进行 -- 操作,然后再放回内存中,将原来的值覆盖。我们这么说,这个过程是不是变得很慢了呢,所以在我们读取 ticket 之后,其他线程也来读取了,最后我们执行一圈后,如果他们都是一起执行完的,那么原来1000的值就变成了999,他们都抢到了第1000张票,这就是重复抢到同一张票的原因。出现负数也是这个原因,只不过不是同一时间做出返回内存的行为,在 CPU 进行计算的时候,要重新读取数据,如果开始时所有线程都 ticket==1,判断这里就能过得去,然后一个线程拿到了最后一张票1,其他三个线程就拿到了“假票”0、-1、-2,这就是我们要进行进程互斥的原因。
以上就是【Linux】深入理解线程控制的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号