例子:操作共享变量会有问题的售票系统代码
#include
#include
#include
#include using namespace std;//买票逻辑
int tickets = 1000; // 在并发访问的时候,导致了我们数据不一致的问题!void *getTickets(void *args)
{(void*)args;// pthread_self() 获取该线程的idwhile(true){if(tickets>0){usleep(1000);printf("%p: %d\n", pthread_self(), tickets);tickets--;}else{break;}}
}int main()
{// 创建一个线程pthread_t tid1, tid2, tid3;pthread_create(&tid1, nullptr, getTickets, nullptr);pthread_create(&tid2, nullptr, getTickets, nullptr);pthread_create(&tid3, nullptr, getTickets, nullptr);pthread_join(tid1, nullptr);pthread_join(tid2, nullptr);pthread_join(tid3, nullptr);return 0;
}
我们理想下:最后票数为0。
运行结果
结果竟然是-1。
为什么可能无法获得争取结果?
—(图片摘自相关教材)
初始化互斥量有两种方法:
pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
参数: mutex:要初始化的互斥量 attr:NULL
int pthread_mutex_destroy(pthread_mutex_t *mutex);
销毁互斥量需要注意:
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,失败返回错误号
调用 pthread_ lock 时,可能会遇到以下情况:
改进上面的售票系统:
#include
#include
#include
#include
#include using namespace std;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态分配// 买票逻辑
int tickets = 1000; // 在并发访问的时候,导致了我们数据不一致的问题!void *getTickets(void *args)
{(void *)args;// pthread_self() 获取该线程的idwhile (true){int n = pthread_mutex_lock(&mutex); // 上锁assert(n == 0);if (tickets > 0){usleep(1000);printf("%p: %d\n", pthread_self(), tickets);tickets--;pthread_mutex_unlock(&mutex); // 解锁assert(n == 0);}else{pthread_mutex_unlock(&mutex); // 解锁assert(n == 0);break;}// 抢完票,其实还需要后续的动作usleep(rand() % 200);}
}int main()
{srand((unsigned long)time(nullptr) ^ getpid() ^ 2023);// 创建一个线程pthread_t tid1, tid2, tid3;pthread_create(&tid1, nullptr, getTickets, nullptr);pthread_create(&tid2, nullptr, getTickets, nullptr);pthread_create(&tid3, nullptr, getTickets, nullptr);pthread_join(tid1, nullptr);pthread_join(tid2, nullptr);pthread_join(tid3, nullptr);pthread_mutex_destroy(&mutex); // 销毁锁return 0;
}
#include
#include
#include
#include
#include using namespace std;// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 静态分配// 买票逻辑
int tickets = 1000; // 在并发访问的时候,导致了我们数据不一致的问题!#define THREAD_NUM 5class ThreadData
{
public:ThreadData(const string &n, pthread_mutex_t *pm) : tname(n), pmtx(pm){}string tname;pthread_mutex_t *pmtx;
};
void *getTickets(void *args)
{// pthread_self() 获取该线程的idThreadData *mutex = (ThreadData *)args;while (true){int n = pthread_mutex_lock(mutex->pmtx); // 上锁assert(n == 0);if (tickets > 0){usleep(1000);printf("%s: %d\n", mutex->tname.c_str(), tickets);tickets--;pthread_mutex_unlock(mutex->pmtx); // 解锁assert(n == 0);}else{pthread_mutex_unlock(mutex->pmtx); // 解锁assert(n == 0);break;}// 抢完票,其实还需要后续的动作usleep(rand() % 200);}delete mutex;return nullptr;
}int main()
{srand((unsigned long)time(nullptr) ^ getpid() ^ 2023);pthread_mutex_t mutex;pthread_mutex_init(&mutex, nullptr);pthread_t t[THREAD_NUM];// 创建线程for (int i = 0; i < THREAD_NUM; ++i){string name = "thread ";name += to_string(i + 1);ThreadData *td = new ThreadData(name, &mutex);pthread_create(t + i, nullptr, getTickets, td);}// 等待线程for (int i = 0; i < THREAD_NUM; ++i){pthread_join(t[i], nullptr);}pthread_mutex_destroy(&mutex); // 销毁锁return 0;
}
如果多线程访问同一个全局变量,并对它进行数据计算,多线程会互相影响;避免方法:
加锁就是串行执行。
加锁了之后,线程在临界区中,会切换,没有时序问题。
我是一个线程,我不申请锁,就是单纯的访问临界资源! 这是一种错误的编码方式。
在没有持有锁的线程看来,对它最有意义的情况只有两种:
要访问临界资源,每一个线程都必须现申请锁,每一个线程都必须先看到同一把锁并且可以访问它,即锁本身就是一种共享资源。那么谁来保证锁的安全呢??为了保证锁的安全,申请和释放锁,必须是原子滴
锁自身保证的(上面的伪代码)—设计者这样设计滴
在执行流视角,是如何看待CPU上面的寄存器的?