Linux面试关键代码

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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值