c++ 多线程 信号量简单使用
完成一个多线程demo,保证三个线程执行顺序,即abc顺序打印
代码示例:
#include <iostream>
#include <semaphore.h>
#include <memory>
#include <thread>
using namespace std;
sem_t firstJobDone; // c++ 线程如果执行成员函数会对this下的成员做一份拷贝,所以信号量不能作为 Foo 的成员变量。
sem_t secondJobDone;
class Foo : public std::enable_shared_from_this<Foo>{
public:
int v;
public:
Foo() {
sem_init(&firstJobDone, 1, 0);
sem_init(&secondJobDone, 1, 0);
}
void first() {
cout<<'a'<<endl;
sem_post(&firstJobDone);
//sem_getvalue(&firstJobDone,&v);
//cout<<"1done:"<<v<<"addr:"<<&firstJobDone<<endl;
}
void second() {
//sleep(2);
//sem_getvalue(&firstJobDone,&v);
//cout<<"11done:"<<v<<"addr:"<<&firstJobDone<<endl;
sem_wait(&firstJobDone);
cout<<'b'<<endl;
sem_post(&secondJobDone);
}
void third() {
sem_wait(&secondJobDone);
cout<<'c'<<endl;
}
std::shared_ptr<Foo> get_this(){
return shared_from_this();
}
};
int main(){
auto foo_ptr = make_shared<Foo>();
// std::thread t{[]{cout<<"xxx";}};
std::thread t1{&Foo::first,*foo_ptr};
std::thread t2{&Foo::second,*foo_ptr};
std::thread t3{&Foo::third,*foo_ptr}; // c++ 获取成员函数指针的指定写法,并且需要传入this指针,因为成员函数第一个参数是this
// std::thread t1{foo_ptr->first,*foo_ptr}; // error
// std::thread t1{&(foo_ptr->first),*foo_ptr}; // error
t1.join();
t2.join();
t3.join();
return 0;
}
互斥量的使用可以用 mutex 库,lock/unlock,lock_guard(自动解锁,不可以手动lock/unlock),unique_lock(可以手动lock/unlock)
给出 leetcode 1195 的解法:
#include <semaphore.h>
#include <functional>
#include <thread>
using namespace std;
class FizzBuzz {
private:
int n;
int cur;
sem_t sem_fizz;
sem_t sem_buzz;
sem_t sem_fizz_buzz;
sem_t sem_num;
public:
FizzBuzz(int n) {
this->n = n;
cur = 0;
sem_init(&sem_fizz, 0, 0);
sem_init(&sem_buzz, 0, 0);
sem_init(&sem_fizz_buzz, 0, 0);
sem_init(&sem_num, 0, 1);
}
// printFizz() outputs "fizz".
void fizz(function<void()> printFizz) {
while(cur <= n){
sem_wait(&sem_fizz);
if(cur > n) break;
printFizz();
sem_post(&sem_num);
}
}
// printBuzz() outputs "buzz".
void buzz(function<void()> printBuzz) {
while(cur <= n){
sem_wait(&sem_buzz);
if(cur > n) break;
printBuzz();
sem_post(&sem_num);
}
}
// printFizzBuzz() outputs "fizzbuzz".
void fizzbuzz(function<void()> printFizzBuzz) {
while(cur <= n){
sem_wait(&sem_fizz_buzz);
if(cur > n) break;
printFizzBuzz();
sem_post(&sem_num);
}
}
// printNumber(x) outputs "x", where x is an integer.
void number(function<void(int)> printNumber) {
while(++cur <= n){
sem_wait(&sem_num);
if(cur % 3 == 0 && cur % 5 == 0){
sem_post(&sem_fizz_buzz);
}else if(cur % 3 == 0){
sem_post(&sem_fizz);
}else if(cur % 5 == 0){
sem_post(&sem_buzz);
}else{
printNumber(cur);
sem_post(&sem_num);
}
}
// 以下三个post通过更新sem_fizz等信号量,调动其他线程运行,进而结束所有线程
sem_post(&sem_fizz);
sem_post(&sem_buzz);
sem_post(&sem_fizz_buzz);
}
};
int main(int argc, char** argv){
FizzBuzz fizzBuzz(15);
std::function<void()> printFizz = [](){printf(" fizz ");};
std::function<void()> printBuzz = [](){printf(" buzz ");};
std::function<void()> printFizzBuzz = [](){printf(" fizzbuzz ");};
std::function<void(int)> printNum = [](int x){printf(" %d ", x);};
std::thread th[4];
th[0] = std::thread(&FizzBuzz::fizz, &fizzBuzz, printFizz);
th[1] = std::thread(&FizzBuzz::buzz, &fizzBuzz, printBuzz);
th[2] = std::thread(&FizzBuzz::fizzbuzz, &fizzBuzz, printFizzBuzz);
th[3] = std::thread(&FizzBuzz::number, &fizzBuzz, printNum);
for(auto &ts : th) {
if(ts.joinable()) ts.join();
}
return 0;
}