关于线程


........................................................................线程.................................................................

线程计算机中独立运行的最小单位,在运行时占用很少的系统资源。

Linux操作系统支持多线程操作,在一个进程内生成许多个线程,即一个进程可以拥有一至多个线程。


1.创建线程 :pthread_create()

int pthread_create(pthread_t *thread,pthread_attr_t *attr,void* (*start_routine)(),void *arg);

thread:当线程创建成功时,用来返回创建的线程ID

attr:用于指定线程的书写,NULL表示使用默认属性。

start_routine:函数指针,指向线程创建后要调用的函数。

arg:该参数指向传递给线程函数的参数。

线程创建成功时,pthread_create函数返回0,若不为0,则说明创建线程失败。

相关系统函数:

pthread_t pthread_self():获取本线程的线程ID

int pthread_once(pthread_once_t *once_control,void(*init_routine)()):用来保证init_routine线程函数在进程中执行一次。


请看下面例子:

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<errno.h>
#include<stdlib.h>

#if 1
int* thread()
{
	pthread_t newtid;
	printf("this is a thread,thread ID = %u\n",newtid);
	return NULL;
}


int main()
{
	pthread_t  tid;
	printf("main thread,ID is %u\n",pthread_self());  //打印主线程的ID
	if(pthread_create(&tid,NULL,(void*)thread,NULL)!=0)
	{
		printf("thread creation failed\n");
		exit(1);
	}
	sleep(1);
	exit(0);
}
#endif

运行结果如下:


程序先打印出主线程的ID,然后打印新创建的线程的ID


也可以同时创建多个线程,分别打印线程信息。

#if 1
//pthread_self()--获取自身线程ID号
void* thread_fun(void *arg)
{
  printf("this id fun,tid = %x.pid = %d\n",pthread_self(),getpid());
  printf("fun ends\n");
}
void* thread_fun1(void *arg)
{
 printf("this id fun1,tid = %x.pid = %d\n",pthread_self(),getpid());
 printf("fun1 ends\n");

}
int main()
{
  pthread_t tid1,tid2;
  int res = pthread_create(&tid1,NULL,thread_fun,NULL);
  if(res != 0)
   {
     perror("pthread_create");
     exit(1);
   }
  else
  {
    printf("tid1 = %x,pid = %d\n",tid1,getpid());
    sleep(1);  //加入睡眠函数 会等待子线程执行
  }
  res = pthread_create(&tid2,NULL,thread_fun1,NULL);
  if(res != 0)
   {
       perror("pthread_create tid2");
       exit(1);
   }
  else
   {
       printf("tid2 = %x.pid = %d\n",tid2,getpid());
       sleep(1);
   }
    
   int i;
  for(i=0;i<10;i++)
   {
        printf("This is Main.\n");
   }
    return 0;
}
#endif


2.pthread_join()---等待一个线程的结束。

3.pthread_exit()---使线程退出。

pthread_join用来等待一个线程的结束。相当于进程中的wait(),

需要注意的是:一个线程仅允许一个进程使用pthread_join()等待他的终止,并且被等待的线程应该处于可join状态。

例子如下:

/*
  pthread_join()--等待一个线程的结束或者终止一个线程 类似于进程中的wait()函数。
函数原型  int pthread_join(pthread_t thread, void **retval);
                            当前进程ID号     
注:一个线程仅允许一个线程使用pthread_join()等待他的终止
 pthread_exit() --结束线程
 */
#if 1
int fun(int a,int b)
{
   return a + b;
}
typedef int(*pFun)(int ,int);

void* thread_fun(void *arg)
{
	pFun pfun = (pFun)arg;
	printf("value = %d\n",pfun(10,20));

	char *exit_code = "I am Child Thread,finsh.\n";
	pthread_exit(exit_code);
}

int main()
{
	pthread_t tid;
	int count = 5;
	int res = pthread_create(&tid,NULL,thread_fun,fun);
	if(res != 0)
	{
		perror("pthread_create");
		exit(1);
	}
	int i;
	for(i=0;i<10;++i)
	{
		printf("This is Main.\n");
	}
	char *retval;
	pthread_join(tid,(void**)&retval);  会阻塞主线程,等待子线程thread_fun结束
	printf("exit code = %s\n",retval);
	return 0;
}
#endif

前面我们说过一个进程可以创建多个线程,下面我们看一个例子。

#if 1
//一个进程创建多个线程的方式--添加循环
#define MAX_THREAD_SIZE 10
void* thread_fun(void *arg)
{
	int index=*(int*)arg;
	printf("[%d] thread start up.\n",index);
	pthread_exit(NULL);
}
int main()
{
	pthread_t tid[MAX_THREAD_SIZE];
	int i;
	for(i=0;i<MAX_THREAD_SIZE;++i)
	{
		pthread_create(&tid[i],NULL,thread_fun,&i);
		sleep(1);
	}
	for(i=0;i<MAX_THREAD_SIZE;++i)
	{
		pthread_join(tid[i],NULL);
	}
	return 0;
}
#endif


运行结果如下:


上述代码采用循环的方式创建了10个线程,依次循环创建多个线程。



**********************线程同步****************************
线程最大的特点就是资源的共享性,但是资源共享中的同步问题是多线程编程的难点。
因此,有几种方式可以处理线程间的同步问题,分别是:
 1.互斥量
 2.信号量
 3.条件变量
 4.读写锁



###########互斥量###########
..........互斥量...............
线程对共享资源访问要想达到同步,即 两个线程只能有一个运行 -通过互斥量实现
互斥量通过锁机制来实现线程间的同步,在同一时刻只允许一个线程执行一个关键部分。
 
互斥量的 两种初始化方式;
 1. int pthread_mutex_init(pthread_mutex_t *restrict mutex,
              const pthread_mutexattr_t *restrict attr);//动态初始化
  2. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //静态赋值


初始化完成后,就可以给互斥锁加锁。
互斥量的两个状态:
pthread_mutex_lock(pthread_mutex_t *mutex); 加锁
加锁时,如果mutex已经被锁住,当前尝试加锁的线程就会阻塞,直到互斥锁被其他线程释放。当函数返回时,说明互斥锁已经被当前线程成功加锁。
pthread_mutex_unlock(pthread_mutex_t *mutex);解锁
解锁时,满足两个条件:一是互斥锁必须处于加锁状态,二是调用本函数的线程必须是给互斥锁加锁的线程。解锁后如果还有其他线程在等待互斥锁,等待队列中的第一个线程将获得互斥锁
当一个互斥锁使用完毕后,必须进行清除,释放它所占用的资源。
注意:清除锁时要求当前处于开放状态,若锁处于锁定状态,函数返回EBUSY。
摧毁函数:int pthread_mutex_destroy(pthread_mutex_t *mutex)


...................................条件变量...................
(同互斥量相似)

1.初始化函数

int pthread_cond_init(pthread_cond_t *restrict cond,
              const pthread_condattr_t *restrict attr);

2.等待函数:   int pthread_cond_wait(pthread_cond_t *restrict cond,
              pthread_mutex_t *restrict mutex);
此函数释放由mutex指向的互斥锁,同时使当前线程关于cond指向的条件变量阻塞,直到条件被信号唤醒
  两大功能:阻塞的同时还可以解锁 
              pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
3.摧毁函数:  int pthread_cond_destroy(pthread_cond_t *cond);
只有在没有线程等待该条件变量时才能清除这个环境变量,否则返回EBUSY

#if 1
//pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //初始化方式1:静态赋值法
//pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
//pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;

pthread_mutex_t mutex;
pthread_cond_t cond;
void* thread1(void *arg)
{
	while(1)
	{
		printf("thread1 is running!\n");
		pthread_mutex_lock(&mutex);
		printf("This is thread1.wait....\n");
		pthread_cond_wait(&cond,&mutex);
//无wait函数时,fun1执行完走fun2,
		printf("thread1 wake up.\n");
		pthread_mutex_unlock(&mutex); //在同一个进程中的线程,如果加锁后没有解//锁,则其他线程则无法获得该锁
		sleep(3);
	}
}

void* thread2(void *arg)
{
	while(1)
	{
		printf("thread2 is running!\n");  
		pthread_mutex_lock(&mutex);
		printf("This is thread2.wait……\n");
		pthread_cond_wait(&cond,&mutex);
		printf("thread2 wake up\n");
		pthread_mutex_unlock(&mutex);
		sleep(1);
	}
}

int main()
{
	pthread_t tid1,tid2;
    
	printf("condition variable study!\n");

	pthread_mutex_init(&mutex, NULL);//通过初始化函数初始化互斥锁
        pthread_cond_init(&mutex,NULL); //初始化条件变量
	pthread_create(&tid1,NULL,thread1,NULL);
	sleep(1);   //使thread1先运行
	pthread_create(&tid2,NULL,thread2,NULL);

do{
//激活一个等待条件成立的过程,存在多个等待线程时,按照入队顺序激活。
	pthread_cond_signal(&cond); 	
	}while(1);
	
	pthread_exit(0);
	return 0;
}
#endif


从运行结果来看,thread1和thread2通过条件变量同步运行,在线程函数thread1中可以看到条件变量使用时要配合互斥锁使用,这样可以防止多个线程同时请求。
即互斥量扮演着一个保护者的角色,保证条件变量能被正确的修改。

pthread_cond_wait(),调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列之前,mutex保持锁定状态,并在线程挂起前解锁。


写一个小程序来复习学习的线程操作以及线程同步

创建两个线程,分别执行计数功能,互斥操作分别打印奇数和偶数

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>  //memset
#if 1
#define MAX_COUNT 10
int count = 1;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
void* fun1(void *arg)
{
	sleep(3);
	while(count <= MAX_COUNT)
	{
             pthread_mutex_lock(&mutex);
		if(count % 2 == 1) //奇数时执行,偶数时阻塞去执行另一个线程
		{
			printf("fun1:%d\n",count);
			count++;
			sleep(1);
			pthread_cond_signal(&cond);//发送信号,唤醒等待的进程
        	}
		else
		{
			pthread_cond_wait(&cond1, &mutex);
			printf("This is oushu\n");
		}
              pthread_mutex_unlock(&mutex);
	}

}
void* fun2(void *arg)
{
	while(count <= MAX_COUNT)
	{
              pthread_mutex_lock(&mutex);
		if(count%2 == 0)//偶数时执行,奇数时阻塞去执行另一个线程
		{  
			printf("fun2:%d\n",count);
			count++;
			sleep(1);
			pthread_cond_signal(&cond1);

		}  
		else
		{
			pthread_cond_wait(&cond, &mutex);
			printf("This is jishu\n");
		}
              pthread_mutex_unlock(&mutex);
	}


}
int main()
{
	pthread_t tid1,tid2;
	pthread_create(&tid1,NULL,fun1,NULL);
	pthread_create(&tid2,NULL,fun2,NULL);
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	return 0;
}
#endif

运行结果如下:












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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值