多线程实现方法(加锁 不加锁)

线程创建原因

在多线程应用程序中,当多个线程共享相同的内存时,如同时访问一个变量时,需要确保每个线程看到一致的数据视图,即保证所有线程对数据的修改是一致的。
一个典型的例子是,在一个多线程程序中,两个及以上个线程对同一个变量i执行i++操作,结果得到的值并不如顺序执行所预期的那样。这就是线程间不同步的一个例子。

== 每个线程使用的变量都是其他线程不会读取和修改的
变量是只读的== 则可以不用加锁

==发现如果把pthread_mutex_unlock放在usleep()函数后面的话,其他4个线程就一直阻塞在lock上.
查了下资料,原来当这个线程从usleep()醒来后,unlock掉mutex之后,线程调度程序并不会立即让其他线程去占有这个mutex,由于当前线程刚从还有剩余时间片,于是又得到了这个mutex,而其他的线程就没有机会得到这个mutex.
解决方法就是把usleep(500000)和pthread_unlock_mutex(&conn_mutex)换个位置
结论:不要持有一个mutex太久,特别是不能在sleep()的时候持有一个mutex ==

流程如下

1:锁初始化;
static pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);

2:初始化条件变量:为了避免死锁的发生;
pthread_cond_init(&cond, NULL);//初始化一条件变量:是给线程共用的,防止锁死(进入某个线程,发现条件不成立,出不来)。

3:设置调度参数
setup_sched_parameters(&tattr, 99); //设置调度参数 包括设置 inheritsched(继承性) 和pthread_attr_setschedpolicy(线程策略)
pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED) 这个函数有2个参数
attr :表示线程属性。
另一个参数有2种 :
PTHREAD_EXPLICIT_SCHED,线程能继承自己设置优先级和调度策略有效
PTHREAD_INHERIT_SCHED, 新的线程继承创建线程的策略和参数!

ret = pthread_attr_setschedpolicy(attr, prio ? SCHED_FIFO : SCHED_OTHER);
设置线程优先级和调度参数,如果成功返回,则支持SCHED_FIFO(先进先出),否则SCHED_FIFO(其他方法)

/* SCHED_OTHER是不支持优先级使用的, 而SCHED_FIFO和SCHED_RR 支持优先级的使用, 他们分别为1和99, 数值越大优先级越高.
注意:
> 此处的SCHED_FIFO是允许被高优先级抢占的!
> 也就是有高优先级的必须先运行
> SCHED_RR是设置一个时间片
> 当有SCHED_FIFO或SCHED_RR策赂的线程在一个条件变量上等持或等持加锁同一个互斥量时,它们将以优先级顺序被唤醒。即,如果一个低优先级的SCHED_FIFO线程和一个高优先织的SCHED_FIFO线程都在等待锁相同的互斥且,则当互斥量被解锁时,高优先级线程将总是被首先解除阻塞。*/

4: 创建线程
ret = pthread_create(&pth_task0, &tattr, test_thread, NULL);//创建线程1,函数处理test_thread

5:去除初始化
函数将对象属性初始化为其缺省值。分配一些存储空间,所以需要下面的函数删除初始化期间分配的存储空间。
属性对象被销毁,并不影响线程的属性。
pthread_attr_destroy(&tattr);

加锁很详细

#include <iostream>
#include <pthread.h>
#include <signal.h>
#include <windows.h>
//#pragma comment(lib,"x64/pthreadVC2.lib")
using namespace std;
static int condition = 0;   //所谓的全局变量,有线程进入的条件
static int value = 0;
static pthread_mutex_t mutex;
static pthread_cond_t cond;

pthread_attr_t tattr;//线程1属性对象   
// pthread_attr_t//主要包括scope属性、detach属性、堆栈地址、堆栈大小、优先级。在pthread_create中,把第二个参数设置为NULL的话,将采用默认的属性配置。
pthread_attr_t tattr1;//线程2属性对象
pthread_t pth_task0;   //pthread_t声明线程ID
pthread_t pth_task1;

static void signal_handler(int sig)
{
	exit(0);
}

static void setup_sched_parameters(pthread_attr_t *attr, int prio)
{
	struct sched_param p; //描述调度参数的结构概要
	int ret;

	ret = pthread_attr_init(attr); //线程初始化
	if (ret)
	{
		//error(1, ret, "pthread_attr_init()");
	}

	ret = pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED); //必须先设置inheritsached 为PTHREAD_EXPLICIT_SCHED,线程才能继承自己设置优先级和调度策略有效
																	 //另外一个参数PTHREAD_INHERIT_SCHED, 新的线程继承创建线程的策略和参数!
	if (ret)
	{
		//error(1, ret, "pthread_attr_setinheritsched()");
	}

	ret = pthread_attr_setschedpolicy(attr, prio ? SCHED_FIFO : SCHED_OTHER); // 设置线程优先级和调度参数,如果成功返回,则支持SCHED_FIFO(先进先出),否则SCHED_FIFO(其他方法)
	                     /*SCHED_OTHER是不支持优先级使用的, 而SCHED_FIFO和SCHED_RR
		                  支持优先级的使用, 他们分别为1和99, 数值越大优先级越高.

		                    注意:
							> 此处的SCHED_FIFO是允许被高优先级抢占的!
							> 也就是有高优先级的必须先运行
							> SCHED_RR是设置一个时间片
							> 当有SCHED_FIFO或SCHED_RR策赂的线程在一个条件变量
							上等持或等持加锁同一个互斥量时,它们将以优先级顺序被唤
							醒。即,如果一个低优先级的SCHED_FIFO线程和一个高优先
							织的SCHED_FIFO线程都在等待锁相同的互斥且,则当互斥量
							被解锁时,高优先级线程将总是被首先解除阻塞。*/
	if (ret)
	{
		//error(1, ret, "pthread_attr_setschedpolicy()");
	}

	/* Set scheduling priority  设置调度优先级*/
	p.sched_priority = prio;
	ret = pthread_attr_setschedparam(attr, &p); //用来设置线程的调度参数
	                                           // 前提条件是这个参数仅当调度策略为实时(即SCHED_RR或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为 0 。
	if (ret)
	{
		//error(1, ret, "pthread_attr_setschedparam()");
	}
}

static void* test_thread(void* arg)
{

	while (1)
	{
		/*上锁*/
		pthread_mutex_lock(&mutex);
		while (condition <= 0)
		{
			/*条件不满足,等待条件,释放互斥锁*/
			//printf("wait condition %lx\n", (long)pthread_self());
			pthread_cond_wait(&cond, &mutex); 
		}

		//printf("get lock thred Id %lx\n", (long)pthread_self());
		//sleep(5);
		condition--;

		//printf("unlock thred Id %lx, value:%d, condition:%d\n",
			//(long)pthread_self(),
		//	++value,
		// condition);

		/*解锁退出*/
		pthread_mutex_unlock(&mutex);
		Sleep(1);
		cout << "线程2" << endl;

	}

}

static void* test2_thread(void* arg)
{

	while (1)
	{
		/*上锁*/
		pthread_mutex_lock(&mutex);
		while (condition <= 0)
		{
			/*条件不满足,等待条件*/
			//printf("wait condition %lx\n", (long)pthread_self());
			pthread_cond_wait(&cond, &mutex);
		}

		//printf("get lock thred Id %lx\n", (long)pthread_self());
		//sleep(5);
		condition--;

		//printf("unlock thred Id %lx, value:%d, condition:%d\n",
		//(long)pthread_self(),
		//	++value,
		// condition);

		/*解锁退出*/
		pthread_mutex_unlock(&mutex);
		Sleep(1);
		cout << "线程3" << endl;

	}

}


int main(int argc, char** argv)
{
	/*main函数功能:第一步:设置好锁和线程参数并创建线程
	                第二步:main函数主线程来解锁哪个线程,实现同步处理
						*/
	int ret = -1;

	signal(SIGTERM, signal_handler); //请求中止进程,kill命令缺省发送
	signal(SIGINT, signal_handler); //由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程??不太懂

	pthread_mutex_init(&mutex, NULL); //锁初始化
	pthread_cond_init(&cond, NULL);//初始化一条件变量:是给线程共用的,防止锁死(进入某个线程,发现条件不成立,出不来)。

	setup_sched_parameters(&tattr, 99); //设置调度参数 包括设置inheritsched 和pthread_attr_setschedpolicy
	ret = pthread_create(&pth_task0, &tattr, test_thread, NULL);//创建线程1,函数处理test_thread
	if (ret)
	{
		//printf("create thread:%s\n", strerror(ret));
		cout << "线程11" << ret << endl;
		return -1;
	}

	pthread_attr_destroy(&tattr);

	setup_sched_parameters(&tattr1, 99);
	ret = pthread_create(&pth_task1, &tattr1, test2_thread, NULL);
	if (ret)
	{
		//printf("create thread:%s\n", strerror(ret));
		cout << "线程22" << ret << endl;
		return -1;
	}

	pthread_attr_destroy(&tattr1);

	while (1)
	{ 
		Sleep(5); //sleep作用,为了暂缓一段时间在使用,防止cpu占用过高。

		/* 主线程获取锁 */
		pthread_mutex_lock(&mutex);
		printf("main thread locked\n");

		condition++;
		//printf("add condition thread id %lx\n", (long)pthread_self());

		/* 主线程解锁 */
		printf("main thread unlocked\n");
		pthread_mutex_unlock(&mutex);

		/* 主线程唤醒在条件上等待的线程 */
		pthread_cond_signal(&cond);

		/* 主线程唤醒所有等待线程 */
		//	pthread_cond_broadcast(&cond);
	}

	pthread_join(pth_task0, NULL);
	pthread_join(pth_task1, NULL);

	return 0;
}

不加锁此时注意不要在多线程内加全局变量

#include <iostream>
#include <pthread.h>
#include <signal.h>
#include <windows.h>
//#pragma comment(lib,"x64/pthreadVC2.lib")
using namespace std;

#define NUM_THREADS 2 //线程数  

void* say_hello(void* args)
{

	cout << "hello..." << endl;
	return 0;
} //函数返回的是函数指针,便于后面作为参数 

void* say_goodbye(void* args)
{
	cout << "good bye" << endl;
	return 0;
}

int main() {

	cout << "babb" << endl;

	pthread_t tids[NUM_THREADS]; //线程id 数组 
for (int i = 0; i < NUM_THREADS; ++i)
	{
		int ret = pthread_create(&tids[0], NULL, say_hello, NULL); //参数:创建的线程id,线程参数,线程运行函数的起始地址,运行函数的参数  
	if (ret != 0) //创建线程成功返回0  
		{
			cout << "pthread_create error:error_code=" << ret << endl;
		}
		int ret_2 = pthread_create(&tids[1],NULL,say_goodbye,NULL);
		if (ret_2 != 0)
 	{
			cout << "pthread_create error:error_code=" << ret_2 << endl;
		}
}
	pthread_exit(NULL); //等待各个线程退出后,进程才结束,否则进程强制结束,线程处于未终止的状态  
    system("pause");
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值