常考代码集合
c++11自旋锁的实现
https://blog.csdn.net/dream0130__/article/details/99344317
class Spinlock
{
public:
Spinlock() : flag_(false) {}
~Spinlock() = default;
void lock()
{
bool excepect = false;
while(!flag_.compare_exchange_strong(excepect,true))
{
excepect = false;
}
}
void unlock()
{
flag_.store(false);
}
private:
std::atomic<bool> flag_;
};
无锁队列
https://coolshell.cn/articles/8239.html
https://blog.csdn.net/lucky52529/article/details/101162787
EnQueue(Q, data) //进队列
{
//准备新加入的结点数据
n = new node();
n->value = data;
n->next = NULL;
do {
p = Q->tail; //取链表尾指针的快照
} while( CAS(p->next, NULL, n) != TRUE);
//while条件注释:如果没有把结点链在尾指针上,再试
CAS(Q->tail, p, n); //置尾结点 tail = n;
}
写一个简单String类
先列举一些会用到的知识点
strcpy, strcat等字符串操作函数。
new和delete对于内存的操作符。
对于类的基本概念,拷贝构造,成员运算符的重载。
#include <iostream>
#include <cstring>
using namespace std;
class String{
public:
String()=default; //默认构造函数
String(const char *str); //构造函数
String(const String &str); //复制构造函数
String& operator=(const String &str); //重载赋值运算符
// String operator+(const String &str1, const String &str2); //重载加号运算符
/*用成员方式重载运算符, 不能改变参数的个数
二元运算符用成员重载时, 只需要一个参数, 另一个参数由this指针传入
所以, 像
rmb::operator+(rmb&, rmb&)
都要改成
rmb::operator+(rmb&)
第一个参数由this指针自动传入到函数中去的.
两个参数可以做成友元函数。*/
friend String operator+(const String &str1, const String &str2); //重载加号运算符
~String() {delete []data;}
private:
char *data;
};
//构造函数
String::String(const char *str)
{
if(str)
{
data = new char[strlen(str) + 1];
strcpy(data, str);
}
else
{
data = new char[1];
*data = ‘\0’;
}
}
//复制构造函数
String::String(const String &str)
{
data = new char[strlen(str.data) + 1];
strcpy(data, str.data);
}
//重载赋值运算符
String& String::operator=(const String &str)
{
if(this == &str)
return *this;
else
{//赋值的过程先抹去内存中的内容在进行赋值
delete []data;
data = new char[strlen(str.data) + 1];
strcpy(data, str.data);
return *this;
}
}
//重载加号运算符
//String String::operator+(const String &str1, const String &str2)
String operator+(const String &str1, const String &str2)
{
String tmp;
delete tmp.data;
tmp.data = new char[strlen(str1.data) + strlen(str2.data) + 1];
strcpy(tmp.data, str1.data);
strcat(tmp.data, str2.data);
return tmp;
}
int main()
{
cout << “Hello world!” << endl;
String a(“hello”), b(” world”);
String c = a + b;
//cout << c << endl;
char tmp[4] = {‘a’, ‘b’, ‘c’, ‘d’};
cout << tmp << endl;
return 0;
}
写个main之前之后的函数
#include <iostream>
using namespace std;
__attribute__((destructor)) void test() {
printf("after main\n");
}
void exit_func(void){
printf("after leave main!\n");
}
int main() {
cout<<"main function\n";
atexit(exit_func);
return 0;
}
读写锁
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
pthread_rwlock_t rwlock; //读写锁
int num = 1;
//读操作,其他线程允许读操作,却不允许写操作
void *fun1(void *arg)
{
while (1)
{
pthread_rwlock_rdlock(&rwlock);
printf("read num first===%d\n", num);
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
//读操作,其他线程允许读操作,却不允许写操作
void *fun2(void *arg)
{
while (1)
{
pthread_rwlock_rdlock(&rwlock);
printf("read num second===%d\n", num);
pthread_rwlock_unlock(&rwlock);
sleep(2);
}
}
//写操作,其它线程都不允许读或写操作
void *fun3(void *arg)
{
while (1)
{
pthread_rwlock_wrlock(&rwlock);
num++;
printf("write thread first\n");
pthread_rwlock_unlock(&rwlock);
sleep(2);
}
}
//写操作,其它线程都不允许读或写操作
void *fun4(void *arg)
{
while (1)
{
pthread_rwlock_wrlock(&rwlock);
num++;
printf("write thread second\n");
pthread_rwlock_unlock(&rwlock);
sleep(1);
}
}
int main()
{
pthread_t ptd1, ptd2, ptd3, ptd4;
pthread_rwlock_init(&rwlock, NULL);//初始化一个读写锁
//创建线程
pthread_create(&ptd1, NULL, fun1, NULL);
pthread_create(&ptd2, NULL, fun2, NULL);
pthread_create(&ptd3, NULL, fun3, NULL);
pthread_create(&ptd4, NULL, fun4, NULL);
//等待线程结束,回收其资源
pthread_join(ptd1, NULL);
pthread_join(ptd2, NULL);
pthread_join(ptd3, NULL);
pthread_join(ptd4, NULL);
pthread_rwlock_destroy(&rwlock);//销毁读写锁
return 0;
}
linux系统生产者-消费者
PV原语:是一对原子操作,P操作是资源的–操作,V操作是资源的++操作。PV原语之间的程序运行是不允许被中断的运行。
一、生产者-消费者
N个生产者,M个消费者,一个共享缓冲区,生产者在生产,消费者在消费,如果缓冲区满,生产者停止生产,如果缓冲区空,消费者停止消费。
具体代码例子如下:
信号量类型:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#define NUM 15
int queue[NUM];
sem_t blank_number;
sem_t product_number;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static int p = 0;
static int c = 0;
//生产者线程关联函数
void *produce1(void *arg)
{
while(1)
{
sem_wait(&blank_number);
pthread_mutex_lock(&lock);
queue[p] = rand()%1000;
printf("produce1 %d\n",queue[p]);
p = (p+1)%NUM;
pthread_mutex_unlock(&lock);
sem_post(&product_number);
//sleep(rand()%5);
}
pthread_exit(NULL);
}
void *produce2(void *arg)
{
while(1)
{
sem_wait(&blank_number);
pthread_mutex_lock(&lock);
queue[p] = rand()%1000;
printf("produce2 %d\n",queue[p]);
p = (p+1)%NUM;
pthread_mutex_unlock(&lock);
sem_post(&product_number);
//sleep(rand()%5);
}
pthread_exit(NULL);
}
void *consume1(void *arg)
{
while(1)
{
sem_wait(&product_number);
pthread_mutex_lock(&lock);
printf("consume1 %d\n",queue[c]);
c = (c+1)%NUM;
pthread_mutex_unlock(&lock);
sem_post(&blank_number);
sleep(rand()%5);
}
pthread_exit(NULL);
}
void *consume2(void *arg)
{
while(1)
{
sem_wait(&product_number);
pthread_mutex_lock(&lock);
printf("consum2 %d\n",queue[c]);
c = (c+1)%NUM;
pthread_mutex_unlock(&lock);
sem_post(&blank_number);
sleep(rand()%5);
}
pthread_exit(NULL);
}
int main()
{
pthread_t pid1;
pthread_t pid2;
pthread_t cid1;
pthread_t cid2;
int ret = 0;
//信号量初始化
sem_init(&blank_number,0,NUM);
sem_init(&product_number,0,0);
ret = pthread_create(&pid1,NULL,produce1,NULL);
if(ret < 0)
{
printf("pthread_create error\n");
exit(0);
}
pthread_create(&pid2,NULL,produce2,NULL);
pthread_create(&cid1,NULL,consume1,NULL);
pthread_create(&cid2,NULL,consume2,NULL);
pthread_join(pid1,NULL);
pthread_join(pid2,NULL);
pthread_join(cid1,NULL);
pthread_join(cid2,NULL);
//释放信号量
sem_destroy(&blank_number);
sem_destroy(&product_number);
return 0;
}
条件变量:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
int dish = 0;
pthread_mutex_t lock;
pthread_cond_t full;
pthread_cond_t empty;
//生产者线程相关函数
void* consume(void* arg) {
int id = (int)arg;
while(1) {
pthread_mutex_lock(&lock);
while(dish == 0) {
//消费者的盘子没有苹果开始等待
pthread_cond_wait(&full, &lock);
}
sleep(1);
dish = 0;
//给生产者发送信号
printf("consumer %d get an apple!\n", id);
pthread_cond_signal(&empty);
pthread_mutex_unlock(&lock);
}
pthread_exit(NULL);
}
//消费者线程函数
void* produce(void* arg) {
int id = (int)arg;
while(1) {
pthread_mutex_lock(&lock);
while(dish == 1) {
pthread_cond_wait(&empty, &lock);
}
dish = 1;
printf("producer %d put an apple\n", id);
pthread_cond_signal(&full);
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main() {
pthread_t pid, cid;
int set;
//初始化
pthread_cond_init(&full, NULL);
pthread_cond_init(&empty, NULL);
pthread_mutex_init(&lock, NULL);
//生产者
for(int i = 0; i < 4; i++) {
pthread_create(&pid, NULL, produce, (void*)i);
}
//消费者
for(int i = 0; i<4; i++) {
pthread_create(&cid, NULL, consume, (void *)i);
}
pthread_join(pid, NULL);
pthread_join(cid, NULL);
//条件变量释放和锁
pthread_cond_destroy(&full);
pthread_cond_destroy(&empty);
pthread_mutex_destroy(&lock);
return 0;
}
设计模式
单例模式:
一般情况下,我们建立的一些类是属于工具性质的,基本不用存储太多的跟自身相关的数据,在这种情况下,每次都去new一个对象,即增加了开销,也使得代码更加臃肿。其实只需要一个实例对象就可以。如果采用全局或者静态变量的方式,会影响封装性,难以保证别的代码不会对全局变量造成影响
考虑到这些需要,我们将默认的构造函数声明为私有的,这样就不会被外部所new了,甚至可以将析构函数也声明为私有的,这样就只有自己可以删除自己了。
单例模式的概念:
只允许一个产生一个对象的类
单例模式的实现方法:
1.单例类保证全局只有唯一一个自行创建的实例对象
2.单例类提供获取这个唯一实例的接口
单例模式的优缺点
优点
(1)阻止其他度对象实例化自己的副本,保证所有访问唯一性
(2)类控制了实例化的过程,所以可以灵活的更改实例化的过程
缺点
(1)每次都需要检查是否对象已经生成,造成些微的开销
(2)使用单例对象时,开发人员可能会意外发现自己无法实例化该类
单例模式的分类:
懒汉模式(适用于各种场景):第一次用到类的实力的时候才去实例化
在需要的时候创建对象,懒汉模式需要加入synchronized才可以保证线程安全
饿汉模式(在某些场景下受到限制):单例类定义的时间就进行实例化
在main函数开始的时候即创建对象,饿汉模式是线程安全的
[懒汉和饿汉的实现](https://blog.csdn.net/m0_38059843/article/details/81136240) [添加链接描述](https://blog.csdn.net/lvyibin890/article/details/81943637?utm_source=app) 1:懒汉式 构造函数声明为private或者protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实例的动作有一个public的类方法实现
class singleton
{
protected:
singleton(){}
private:
static singleton* p;
public:
static singleton* instance();
};
singleton* singleton::p = NULL;
singleton* singleton::instance()
{
if (p == NULL)
p = new singleton();
return p;
}
缺点:这个实现在单线程下是正确的,但在多线程情况下,如果两个线程同时首次调用GetInstance方法且同时检测到Instance是NULL,则两个线程会同时构造一个实例给Instance,这样就会发生错误。
2.改进的懒汉式(双重检查锁)
思路:只有在第一次创建的时候进行加锁,当instacne部位空的时候不需要进行加锁的操作
class singleton
{
protected:
singleton()
{
pthread_mutex_init(&mutex);
}
private:
static singleton* p;
public:
static pthread_mutex_t mutex;
static singleton* initance();
};
pthread_mutex_t singleton::mutex;
singleton* singleton::p = NULL;
singleton* singleton::initance()
{
if (p == NULL)
{
pthread_mutex_lock(&mutex);
if (p == NULL)
p = new singleton();
pthread_mutex_unlock(&mutex);
}
return p;
}
之所以用双重检查锁而不是直接上锁,因为直接上锁会影响性能,每次判断都需要被锁定,如果多线程的话,就会造成大量线程的阻塞。
3.内部静态变量的懒汉实现
class singleton
{
protected:
singleton()
{
pthread_mutex_init(&mutex);
}
public:
static pthread_mutex_t mutex;
static singleton* initance();
};
pthread_mutex_t singleton::mutex;
singleton* singleton::initance()
{
pthread_mutex_lock(&mutex);
static singleton obj;
pthread_mutex_unlock(&mutex);
return &obj;
}
4.饿汉式:
饿汉式的特点是一开始就加载了,如果说懒汉式是“时间换空间”,那么饿汉式就是“空间换时间”,因为一开始就创建了实例,所以每次用到的之后直接返回就好了。饿汉模式是线程安全的。
class Singleton{
protected:
Singleton() {};
private:
static Singleton* instance;
static Singletoni* getinstance();
};
Singleton* singleton::instance = new Singleton();
Singleton* Singleton::getinstance() {
return instance;
}
三种工厂模式的C++实现
https://blog.csdn.net/silangquan/article/details/20492293
智能指针
//构造函数
SmartPointer(T* p=0): _ptr(p), _reference_count(new size_t){
if(p)
*_reference_count = 1;
else
*_reference_count = 0; }
//拷贝构造函数
SmartPointer(const SmartPointer& src) {
if(this!=&src) {
_ptr = src._ptr;
_reference_count = src._reference_count;
(*_reference_count)++; } }
//重载赋值操作符
SmartPointer& operator=(const SmartPointer& src) {
if(_ptr==src._ptr) {
return *this; }
releaseCount();
_ptr = src._ptr;
_reference_count = src._reference_count;
(*_reference_count)++;
return *this; }
//重载操作符
T& operator*() {
if(ptr) {
return *_ptr; }
//throw exception }
//重载操作符
T* operator->() {
if(ptr) {
return _ptr; }
//throw exception }
//析构函数
~SmartPointer() {
if (--(*_reference_count) == 0) {
delete _ptr;
delete _reference_count; } }
private:
T *_ptr;
size_t *_reference_count;
void releaseCount() {
if(_ptr) {
(*_reference_count)--;
if((*_reference_count)==0) {
delete _ptr;
delete _reference_count;
}
}
}
1.智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。
2.每次创建类的新对象时,初始化指针并将引用计数置为1;
3/当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;
4.对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;
5.调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。
6.所有的智能指针都会重载 -> 和 * 操作符。智能指针还有许多其他功能,比较有用的是自动销毁。
#include <iostream>
#include <memory>
using namespace std;
template <typename T>
class smartpointer{
public:
//构造函数
smartpointer(T* ptr = NULL) :_ptr(ptr)
{
if (_ptr)//如果实例化了,就建立计数器
{
_count = new size_t(1);
}
else{
_count = new size_t(0);
}
}
//拷贝构造函数(相同的话就不拷贝)
smartpointer(const smartpointer& smp)
{
if (this == &smp)
return;
else{
this->_ptr = smp._ptr;
this->_count = smp._count;
(*this->_count)++;
}
}
//赋值函数(左值减少,右值增加) //特别说明:不是构造函数
smartpointer& operator = (const smartpointer& smp)
{
if (this->_ptr == smp._ptr)
{
return *this;
}
if (this->_ptr)
{
(*this->_count)--;
if ((*this->_count) == 0)
{
delete this->_ptr;
delete this->_count;
}
}
this->_ptr = smp._ptr;
this->_count = smp._count;
(*this->_count)++;
return *this;
}
//重载->和*
T& operator -> ()
{
assert(this->_ptr == NULL);
return (*this->_ptr);
}
T* operator * ()
{
assert(this->_ptr == NULL);
return this->_ptr;
}
//析构函数
~smartpointer()
{
if (*this->_count == 0)
{
delete this->_ptr;
delete this->_count;
cout << "释放" << endl;
}
else{
(*this->_count)--;
if (*this->_count == 0)
{
delete this->_ptr;
delete this->_count;
cout << "释放" << endl;
}
}
}
private:
T* _ptr;
size_t* _count;
};
int main() {
{
//只初始化了两次
smartpointer<int> sp(new int(10));
smartpointer<int> sp2(sp);
smartpointer<int> sp3(new int(20));
sp2 = sp3;
std::cout << sp.use_count() << std::endl;
std::cout << sp3.use_count() << std::endl;
//SmartPointer<int> sp(NULL);
//std::cout << sp.use_count() << std::endl;
}
system("pause");
return 0;
}
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
template<typename T>
class smartpointer{
public:
//构造函数
smartpointer(T* ptr = NULL):_ptr(ptr){
if(_ptr)//如果实例化,就建立计数器
{
_count = new size_t(1);
} else {
_count = new size_t(0);
}
}
//拷贝构造函数(相同的话就不拷贝)
smartpointer(const smartpointer& smp) {
if(this == &smp) return;
else {
this->_ptr = smp._ptr;
this->_count = smp._count;
(*this->_count)++;
}
}
//赋值函数(左值减少,右值增加)
smartpointer& operator= (const smartpointer& smp) {
if(this->_ptr == smp._ptr) return *this;
if(this->_ptr) {
(*this->_count)--;
if((*this->_count) == 0) {
delete this->_ptr;
delete this->_count;
}
}
this->_ptr = smp._ptr;
this->_count = smp._count;
(*this->_count)++;
return *this;
}
//重载-》和*
T& operator ->() {
assert(this->_ptr == NULL);
return (*this->_ptr);
}
T* operator *() {
assert(this->_ptr == NULL);
return this->_ptr;
}
size_t use_count() {
return *(this->_count);
}
//析构函数
~smartpointer() {
if(*(this->_count) == 0) {
delete this->_ptr;
delete this->_count;
printf("释放1\n");
} else {
(*this->_count)--;
if(*this->_count == 0) {
delete this->_ptr;
delete this->_count;
printf("释放2\n");
}
}
}
private:
T* _ptr;
size_t* _count;
};
int main() {
//只初始化了两次
smartpointer<int> sp(new int(10));
smartpointer<int> sp2(sp);
printf("sp.use_count:%d\n",sp.use_count());
printf("sp2.use_count:%d\n",sp2.use_count());
smartpointer<int> sp3(new int(20));
sp2 = sp3;
//std::cout << sp.use_count() << std::endl;
//std::cout << sp3.use_count() << std::endl;
printf("sp.use_count:%d\n",sp.use_count());
printf("sp2.use_count:%d\n",sp2.use_count());
printf("sp3.use_count:%d\n",sp3.use_count());
return 0;
}
C语言多线程之“哲学家就餐”问题
https://blog.csdn.net/weixin_39656575/article/details/80719113
最直接的解决办法(引起死锁)
最直接的解决办法是5只筷子分别设置为初始值为1的互斥信号量。这样可以保证不会有相邻的哲学家同时进餐,但是若5位哲学家同时拿起左筷子,都会因为拿不到右筷子而引起死锁。
优化解决办法
解决办法有很多种:
(1)通过互斥信号量 mutex 对哲学家进餐之前取左侧和右侧筷子的操作进行保护,可以防止死锁的出现。(当第i个哲学家将左右筷子都拿到了才允许其他哲学家拿筷子)
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
pthread_mutex_t mutex[5];
void* dine(void* arg) {
int num = (int)arg;
int left, right;
if(num < 4) {
//前4个人,右手拿自己筷子
right = num;
left = num+1;
} else if(num == 4) {
//最后一个人,右手拿别人筷子
right = 0;
left = num;
}
//吃饭
while(1) {
//右手加锁
pthread_mutex_lock(&mutex[right]);
//尝试抢左手筷子
if(pthread_mutex_trylock(&mutex[left]) == 0){
//吃面
printf("%c 正在吃面。。。\n", num+'A');
//吃完放筷子
pthread_mutex_unlock(&mutex[left]);
}
//解锁
pthread_mutex_unlock(&mutex[right]);
sleep(rand()%5);
}
}
int main(int argc, const char* argv[]) {
pthread_t p[5];
//互斥锁初始化
for(int i = 0; i < 5; i++) {
pthread_mutex_init(&mutex[i], NULL);
}
for(int i = 0; i < 5; i++) {
pthread_create(&p[i], NULL, dine, (void*)i);
}
for(int i = 0; i < 5; i++) {
pthread_join(p[i], NULL);
}
for(int i = 0; i < 5; i++) {
pthread_mutex_destroy(&mutex[i]);
}
return 0;
}
(2)规定奇数号哲学家先拿左筷子再拿右筷子,而偶数号哲学家相反。所以将是 2,3 号哲学家竞争 3 号筷子,4,5 号哲学家竞争 5 号筷子。1 号哲学家不需要竞争。最后总会有一个哲学家能获得两支筷子而进餐。
(3)至多只允许四位哲学家同时去拿左筷子,最终能保证至少有一位哲学家能进餐,并在用完后释放两只筷子供他人使用。此方法能使资源得到有效的利用。
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define N 5
sem_t chopstick[5];//设置5种信号量,右5种不同类型的资源,每一种右1个
sem_t mutex;//最多允许有mutex(4)个哲学家同时拿起筷子
//pthread_mutex_t mutex;//定义互斥
void* philosopher(void* arg) {
//int i = *(int *)arg;
int i = (int) arg;
int left = i;//左筷子的编号和哲学家的编号相同
int right = (i+1)%N;//右筷子的编号为哲学家编号+1
while(1) {
printf("哲学家%d正在思考问题\n", i);
sleep(1);
printf("哲学家%d饿了\n", i);
//pthread_mutex_lock(&mutex);//加锁
sem_wait(&mutex);//如果前4个哲学家同时拿起左筷子,第五个不能同时拿起左筷子,保证至少有一位哲学家能吃到饭,解决(死锁状态)。
sem_wait(&chopstick[left]);
//此时这个哲学家左筷子的信号量-1之后>=0时,表示能继续执行。
printf("哲学家%d拿起了%d号筷子,现在只有一支筷子,不能进餐\n", i, left);
sem_wait(&chopstick[right]);
printf("哲学家%d拿起了%d号筷子\n", i, right);
printf("哲学家%d现在有两支筷子,开始进餐\n", i);
sleep(1);
sem_post(&chopstick[left]);
printf("哲学家%d放下了%d号筷子\n", i, left);
//pthread_mutex_unlock(&mutex);
sem_post(&mutex);//当哲学家释放了左筷子时,信号量m+1
//现在哲学家已经完成进餐,需要放下手中的筷子
sem_post(&chopstick[right]);
printf("哲学家%d放下了%d号筷子\n", i, right);
//sleep(rand()%3);
}
}
int main() {
srand(time(NULL));
pthread_t philo[N];
int philosophers[N];
//pthread_mutex_init(&mutex,NULL);
//信号量初始化
for(int i = 0; i < N; i++) {
philosophers[i] = i;
sem_init(&chopstick[i], 0, 1);
}
sem_init(&mutex,0,4);
//创建线程
for(int i = 0; i < N; i++) {
//pthread_create(&philo[i], NULL, philosopher, &philosophers[i]);
pthread_create(&philo[i], NULL, philosopher, (void*)i);
}
//销毁线程
for(int i = 0; i < N; i++) {
pthread_join(philo[i], NULL);
}
//销毁信号量
for(int i = 0; i < N; i++) {
sem_destroy(&chopstick[i]);
}
//pthread_mutex_destroy(&mutex);//销毁互斥锁
sem_destroy(&mutex);
return 0;
}
linux遍历目录下的所有文件
文件数量:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
int get_file_num(char* root)
{
int total = 0;
DIR* dir = NULL;
// 打开目录
dir = opendir(root);
// 循环从目录中读文件
char path[1024];
// 定义记录xiang指针
struct dirent* ptr = NULL;
while( (ptr = readdir(dir)) != NULL)
{
// 跳过. he ..
if(strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
{
continue;
}
// 判断是不是目录
if(ptr->d_type == DT_DIR)
{
///home/deng/share
sprintf(path, "%s/%s", root, ptr->d_name);
// 递归读目录
total += get_file_num(path);
}
// 如果是普通文件
if(ptr->d_type == DT_REG)
{
total ++;
}
}
closedir(dir);
return total;
}
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("./a.out path");
exit(1);
}
int total = get_file_num(argv[1]);
printf("%s has regfile number: %d\n", argv[1], total);
return 0;
}
打印文件
#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
void printdir(char *dir, int depth)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if((dp = opendir(dir)) == NULL) {
fprintf(stderr,"cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while((entry = readdir(dp)) != NULL) {
lstat(entry->d_name,&statbuf);
if(S_ISDIR(statbuf.st_mode)) {
if(strcmp(".",entry->d_name) == 0 ||
strcmp("..",entry->d_name) == 0)
continue;
printf("%*s%s/\n",depth,"",entry->d_name);
printdir(entry->d_name,depth+4);
}
else printf("%*s%s\n",depth,"",entry->d_name);
}
chdir("..");
closedir(dp);
}
int main(int argc, char* argv[])
{
char *topdir, pwd[2]=".";
if (argc != 2)
topdir=pwd;
else
topdir=argv[1];
printf("Directory scan of %s\n",topdir);
printdir(topdir,0);
printf("done.\n");
return 0;
}
LRU缓存机制
class LRUCache {
public:
LRUCache(int _capacity) :capacity(_capacity){
}
int get(int key) {
if(map.find(key) == map.end()) return -1;
auto key_value = *map[key];
head.erase(map[key]);
head.push_front(key_value);
map[key] = head.begin();
return key_value.second;
}
void put(int key, int value) {
if(map.find(key) == map.end()) {
if(head.size() == capacity) {
map.erase(head.back().first);
head.pop_back();
}
} else{
head.erase(map[key]);
}
head.push_front({key,value});
map[key] = head.begin();
}
private:
int capacity;
list<pair<int, int>> head;
unordered_map<int, list<pair<int, int>>::iterator>map;
};
struct DLinkedNode{
int key, value;
DLinkedNode* prev;
DLinkedNode* next;
DLinkedNode():key(0),value(0),prev(NULL),next(nullptr){}
DLinkedNode(int _key, int _value):key(_key),value(_value),prev(NULL),next(nullptr){}
};
class LRUCache {
public:
LRUCache(int _capacity) :capacity(_capacity), size(0){
//使用伪头部和伪尾部节点
head = new DLinkedNode();
tail = new DLinkedNode();
head->next = tail;
tail->prev = head;
}
int get(int key) {
if(!cache.count(key)) return -1;
// 如果 key 存在,先通过哈希表定位,再移到头部
DLinkedNode* node = cache[key];
moveToHead(node);
return node->value;
}
void put(int key, int value) {
if(!cache.count(key)) {
// 如果 key 不存在,创建一个新的节点
DLinkedNode* node = new DLinkedNode(key, value);
//添加进哈希表
cache[key] = node;
//添加到双向链表的头部
addToHeaad(node);
++size;
if(size > capacity) {
// 如果超出容量,删除双向链表的尾部节点
DLinkedNode* removed = removeTail();
// 删除哈希表中对应的项
cache.erase(removed->key);
// 防止内存泄漏
delete removed;
--size;
}
} else {
// 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
DLinkedNode* node = cache[key];
node->value = value;
moveToHead(node);
}
}
void addToHeaad(DLinkedNode* node) {
node->prev = head;
node->next = head->next;
head->next->prev = node;
head->next = node;
}
void removeNode(DLinkedNode* node) {
node->prev->next = node->next;
node->next->prev = node->prev;
}
void moveToHead(DLinkedNode* node) {
removeNode(node);
addToHeaad(node);
}
DLinkedNode* removeTail() {
DLinkedNode* node = tail->prev;
removeNode(node);
return node;
}
private:
int size;
int capacity;
DLinkedNode* head;
DLinkedNode* tail;
unordered_map<int, DLinkedNode*> cache;
};
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache* obj = new LRUCache(capacity);
* int param_1 = obj->get(key);
* obj->put(key,value);
*/
实现 Trie (前缀树)
class Trie {
public:
/** Initialize your data structure here. */
Trie() {
isEnd = false;
memset(next, 0, sizeof(next));
}
/** Inserts a word into the trie. */
void insert(string word) {
Trie* node = this;
for(char c : word) {
if(node->next[c-'a'] == NULL) {
node->next[c-'a'] = new Trie();
}
node = node->next[c-'a'];
}
node->isEnd = true;
}
/** Returns if the word is in the trie. */
bool search(string word) {
Trie* node = this;
for(char c : word) {
node = node->next[c-'a'];
if(node == NULL) return false;
}
return node->isEnd;
}
/** Returns if there is any word in the trie that starts with the given prefix. */
bool startsWith(string prefix) {
Trie* node = this;
for(char c: prefix) {
node = node->next[c-'a'];
if(node == NULL) return false;
}
return true;
}
private:
Trie* next[26];
bool isEnd;
};
/**
* Your Trie object will be instantiated and called as such:
* Trie* obj = new Trie();
* obj->insert(word);
* bool param_2 = obj->search(word);
* bool param_3 = obj->startsWith(prefix);
*/
单链表奇数升序偶数降序,将链表整体变成升序(C++实现)
#include<iostream>
using namespace std;
//定义链表结构
struct linkList
{
int val;
struct linkList* next;
linkList(int x) :val(x), next(NULL){
}
};
//链表合并排序
linkList* mergelist(linkList* ohead, linkList* jhead){
/*//定义头结点简单
linkList* new_head = new linkList(-1);
linkList* cur = new_head;
//两个链表都存在时继续往下走
while (ohead && jhead){
//
if (ohead->val < jhead->val){
cur->next = ohead;
ohead = ohead -> next;
}
else{
cur->next = jhead;
jhead = jhead->next;
}
cur = cur->next;
}*/
//不定义任何新的节点时
linkList* head = nullptr;
linkList* cur = nullptr;
while (ohead && jhead){
//拿出插入的结点
linkList* p = ohead->val < jhead->val ? ohead : jhead;
if (p == ohead)
ohead = ohead->next;
if (p == jhead)
jhead = jhead->next;
//判断此时是否是空结点
if (head == nullptr){
head = p;
cur = p;
}
else{
cur->next = p;
cur = cur->next;
}
}
//判断两个链表是否为空,将不为空的链表接在新链表的后面
if (ohead == nullptr)
cur->next = jhead;
if (jhead == nullptr)
cur->next = ohead;
return head;
}
//奇结点链表反转
linkList* reveslist(linkList* jhead){
if (jhead->next == nullptr)
return jhead;
linkList* pre = jhead;
linkList* mid = jhead->next;
linkList* last = mid->next;
while (last){
//反转
mid->next = pre;
//整体后移
pre = mid;
mid = last;
last = last->next;
}
//此时最后的mid结点还没有反转
mid->next = pre;
//第一个结点还有反转
jhead->next = nullptr;
return mid;
}
//链表拆分 偶结点升序,奇结点降序
linkList* splitlist(linkList* head){
//判断临界点
if (head == nullptr || head->next == nullptr)
return head;
//定义拆分后的链表
linkList* ohead = nullptr;
linkList* ocur = nullptr;
linkList* jhead = nullptr;
linkList* jcur = nullptr;
int num = 0;
while (head){
if ((num & 1) == 0){
if (ohead == nullptr){
ohead = head;
ocur = head;
}
else{
ocur->next = head;
ocur = ocur->next;
}
}
else{
if (jhead == nullptr){
jhead = head;
jcur = head;
}
else{
jcur->next = head;
jcur = jcur->next;
}
}
head = head->next;
num++;
}
//将奇偶数链表与之前链表断开
ocur->next = nullptr;
jcur->next = nullptr;
linkList* rejhead = reveslist(jhead);
return mergelist(ohead, rejhead);
}
int main(int argc, char * argv){
linkList p0(1), p1(100), p2(11), p3(60),p4(50),p5(30);
p0.next = &p1;
p1.next = &p2;
p2.next = &p3;
p3.next = &p4;
p4.next = &p5;
linkList * result = splitlist(&p0);
while (result){
cout << result->val << " ";
result = result->next;
}
cout << endl;
system("pause");
return 0;
}
linux c++实现两个线程轮流打印1~100
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
pthread_cond_t cond_odd = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_even = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex_x = PTHREAD_MUTEX_INITIALIZER;
int kCount = 1;
void * countOdd(void * arg){
for(int i=0; i<100;i++){
pthread_mutex_lock(&mutex_x);
if(kCount < 100){
// 当前kCount是偶数,等待
if((kCount%2) == 0) pthread_cond_wait(&cond_odd, &mutex_x);
// 打印奇数
printf("Current Thread: %s, Current Count: %d.\n", (char *)arg, kCount);
// 变成偶数
kCount++;
if((kCount%2) == 0){
pthread_cond_signal(&cond_even);
}
}
pthread_mutex_unlock(&mutex_x);
}
}
void * countEven(void *arg){
for(int i=0;i<100;i++){
pthread_mutex_lock(&mutex_x);
if(kCount < 100){
// 当前kCount是奇数,等待
if((kCount%2) == 1) pthread_cond_wait(&cond_even, &mutex_x);
// 打印偶数
printf("Current Thread: %s, Current Count: %d.\n", (char*)arg, kCount);
// 变成奇数
kCount++;
if((kCount%2) == 1){
pthread_cond_signal(&cond_odd);
}
}
pthread_mutex_unlock(&mutex_x);
}
}
int main(int argc, char* argv[]){
pthread_t tids[2];
int i;
if(pthread_create(&tids[0], NULL, countOdd, (void*)("1"))){
printf("pthread_creat_error");
}
if(pthread_create(&tids[1], NULL, countEven, (void*)("2"))){
printf("pthread_creat_error");
}
sleep(3);
for(i = 0;i < 2; i++){
if(pthread_join(tids[i], NULL)){
printf("pthread_join error");
return -1;
}
}
return 0;
}