linux进程同步 centos查看进程命令

大家好,关于linux进程同步很多朋友都还不太明白,今天小编就来为大家分享关于centos查看进程命令的知识,希望对各位有所帮助!

Linux内核中的同步机制:进程的同步同步机制,线程的同步机制

在Linux内核的世界里,同步机制是确保多进程并发执行时资源合理访问的核心手段。同步与互斥,如同一对孪生守护者,守护着数据的完整性与系统的稳定性。当多个进程竞相争夺同一资源时,同步规则便显得尤为重要,它规定了访问的秩序,防止了死锁的滋生。

死锁,这个术语描绘了进程间的恶性循环,每个进程都在等待其他进程释放资源。为避免这种困境,开发者应用了预防、避免、检测和解除策略,其中预防是最优解,通过遵循特定的加锁和解锁规则,比如按顺序加锁解锁,设置超时限制,以及避免不必要的资源请求,来减少死锁的发生。

同步手段多样,原子操作是其中的基础,它们保证操作的完整性,不会因中断或抢占而被打断。例如,atomic_read和atomic_inc这样的函数,确保了数据的准确更新。在实战中,如自旋锁(spin_lock)和读写自旋锁(rwlock),以及信号量(semaphore),各有其适用场景。自旋锁适合处理短暂的临界区,而信号量则适用于长时间等待的场景,它们的使用需结合系统资源和CPU消耗进行权衡。

深入理解内核的同步机制,如自旋锁的spin_lock、spin_lock_irqsave,以及读写锁的read_lock和write_lock,能够帮助开发者编写出高效且安全的并发代码。在编写示例中,我们看到临界区的保护(如DEFINE_SPINLOCK(mr_lock))以及中断处理时的互斥策略(如spin_lock_irqsave)。

对于信号量和互斥体(mutex),信号量的sem_init、down和up操作提供了更广泛的同步功能,而mutex的简单接口如mutex_lock和mutex_unlock,使得它成为首选。完成变量(completion)则用于任务间的协作,completion.h>提供了相关头文件支持。

值得注意的是,早期的大内核锁(BKL)已被弃用,取而代之的是更为精细的资源保护策略。RCU(Read-Copy Update)扩展了读写锁,为多线程读写操作提供平衡,但需注意其性能开销。而per_cpu变量在内核中扮演着关键角色,尤其是在中断处理和进程同步中,它们是多处理器协作的基石。

最后,学习Linux内核开发并非孤立的知识,它与进程同步、线程同步、通信机制(如管道、信号等)紧密相连。如果你对内核源码、内存调优、文件系统等主题感兴趣,可以通过课程资源,如973961276群组获取更多学习资料和视频教程。踏上探索Linux内核的旅程,让我们一起领略其深度与魅力吧!

Linux线程及同步

linux多线程

1.线程概述

线程是一个进程内的基本调度单位,也可以称为轻量级进程。线程是在共享内存空间中并发的多道执行路径,它们共享一个进程的资源,如文件描述和信号处理。因此,大大减少了上下文切换的开销。一个进程可以有多个线程,也就

是有多个线程控制表及堆栈寄存器,但却共享一个用户地址空间。

2.线程实现

线程创建pthread_create()

所需头文件#include

<pthread.h>

函数原型int

pthread_create

((pthread_t

*thread,

pthread_attr_t

*attr,

thread:线程标识符

attr:线程属性设置

start_routine:线程函数的起始地址

arg:传递给start_routine的参数

函数返回值

成功:0

出错:-1

线程退出pthread_exit();

所需头文件#include

<pthread.h>

函数原型void

pthread_exit(void

*retval)

函数传入值retval:pthread_exit()调用者线程的返回值,可由其他函数如pthread_join

来检索获取

等待线程退出并释放资源pthread_join()

所需头文件#include

<pthread.h>

函数原型int

pthread_join

((pthread_t

th,

void

**thread_return))

函数传入值

th:等待线程的标识符

thread_return:用户定义的指针,用来存储被等待线程的返回值(不为NULL时)

函数返回值

成功:0

出错:-1

代码举例

1.

#include<pthread.h>

2.

#include<stdio.h>

3.

#include<errno.h>

4.

5.

/*线程1*/

6.

void

thread1()

7.

{

8.

int

i=0;

9.

10.

while(1)

11.

{

12.

printf(thread1:%d/n,i);

13.

if(i>3)

14.

pthread_exit(0);

15.

i++;

16.

sleep(1);

17.

}

18.

}

19.

20.

/*线程2*/

21.

void

thread2()

22.

{

23.

int

i=0;

24.

25.

while(1)

26.

{

27.

printf(thread2:%d/n,i);

28.

if(i>5)

29.

pthread_exit(0);

30.

i++;

31.

sleep(1);

32.

}

33.

}

34.

35.

int

main()

36.

{

37.

pthread_t

t1,t2;

38.

39.

/*创建线程*/

40.

pthread_create(&t1,NULL,(void

*)thread1,NULL);

41.

pthread_create(&t2,NULL,(void

*)thread2,NULL);

42.

/*等待线程退出*/

43.

pthread_join(t1,NULL);

44.

pthread_join(t2,NULL);

45.

return

0;

46.

}

3同步与互斥

<1>互斥锁

互斥锁的操作主要包括以下几个步骤。

互斥锁初始化:pthread_mutex_init

互斥锁上锁:pthread_mutex_lock

互斥锁判断上锁:pthread_mutex_trylock

互斥锁接锁:pthread_mutex_unlock

消除互斥锁:pthread_mutex_destroy

1.

#include<pthread.h>

2.

#include<stdio.h>

3.

#include<errno.h>

4.

5.

int

i=0;/*共享变量*/

6.

pthread_mutex_t

mutex=PTHREAD_MUTEX_INITIALIZER;/*互斥锁*/

7.

8.

void

thread1()

9.

{

10.

int

ret;

11.

while(1)

12.

{

13.

14.

15.

ret=pthread_mutex_trylock(&mutex);/*判断上锁*/

16.

17.

if(ret!=EBUSY)

18.

{

19.

pthread_mutex_lock(&mutex);/*上锁*/

20.

printf(This

is

thread1:%d/n,i);

21.

i++;

22.

pthread_mutex_unlock(&mutex);/*解锁*/

23.

}

24.

sleep(1);

25.

}

26.

}

27.

28.

void

thread2()

29.

{int

ret;

30.

while(1)

31.

{

32.

33.

ret=pthread_mutex_trylock(&mutex);

34.

if(ret!=EBUSY)

35.

{

36.

pthread_mutex_lock(&mutex);

37.

printf(This

is

thread2:%d/n,i);

38.

i++;

39.

pthread_mutex_unlock(&mutex);

40.

}

41.

sleep(1);

42.

}

43.

}

44.

int

main()

45.

{

46.

pthread_t

t1,t2;

47.

pthread_mutex_init(&mutex,NULL);

48.

pthread_create(&t1,NULL,(void

*)thread1,NULL);

49.

pthread_create(&t2,NULL,(void

*)thread2,NULL);

50.

51.

pthread_join(t1,NULL);

52.

pthread_join(t2,NULL);

53.

54.

pthread_mutex_destroy(&mutex);

55.

return

0;

56.

}

<2>信号量

未进行同步处理的两个线程

1.

#include<pthread.h>

2.

#include<stdio.h>

3.

#include<errno.h>

4.

5.

int

i=0;

6.

void

thread1()

7.

{

8.

9.

while(1)

10.

{

11.

printf(This

is

thread1:%d/n,i);

12.

i++;

13.

sleep(1);

14.

}

15.

}

16.

17.

18.

void

thread2()

19.

{

20.

21.

while(1)

22.

{

23.

printf(This

is

thread2:%d/n,i);

24.

i++;

25.

sleep(1);

26.

}

27.

}

28.

29.

int

main()

30.

{

31.

pthread_t

t1,t2;

32.

33.

pthread_create(&t1,NULL,(void

*)thread1,NULL);

34.

pthread_create(&t2,NULL,(void

*)thread2,NULL);

linux 多进程信号同步问题

朋友你好:希望能帮到你。互相学习。

线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点。linux下提供了多种方式来处理线程同步,最常用的是互斥锁、条件变量和信号量。

1)互斥锁(mutex)

通过锁机制实现线程间的同步。同一时刻只允许一个线程执行一个关键部分的代码。

int pthread_mutex_init(pthread_mutex_t*mutex,const pthread_mutex_attr_t*mutexattr);

int pthread_mutex_lock(pthread_mutex*mutex);

int pthread_mutex_destroy(pthread_mutex*mutex);

int pthread_mutex_unlock(pthread_mutex*

(1)先初始化锁init()或静态赋值pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIER

attr_t有:

PTHREAD_MUTEX_TIMED_NP:其余线程等待队列

PTHREAD_MUTEX_RECURSIVE_NP:嵌套锁,允许线程多次加锁,不同线程,解锁后重新竞争

PTHREAD_MUTEX_ERRORCHECK_NP:检错,与一同,线程请求已用锁,返回EDEADLK;

PTHREAD_MUTEX_ADAPTIVE_NP:适应锁,解锁后重新竞争

(2)加锁,lock,trylock,lock阻塞等待锁,trylock立即返回EBUSY

(3)解锁,unlock需满足是加锁状态,且由加锁线程解锁

(4)清除锁,destroy(此时锁必需unlock,否则返回EBUSY,//Linux下互斥锁不占用内存资源

示例代码

#include<cstdio>

#include<cstdlib>

#include<unistd.h>

#include<pthread.h>

#include"iostream"

using namespace std;

pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER;

int tmp;

void* thread(void*arg)

{

cout<<"thread id is"<< pthread_self()<< endl;

pthread_mutex_lock(&mutex);

tmp= 12;

cout<<"Now a is"<< tmp<< endl;

pthread_mutex_unlock(&mutex);

return NULL;

}

int main()

{

pthread_t id;

cout<<"main thread id is"<< pthread_self()<< endl;

tmp= 3;

cout<<"In main func tmp="<< tmp<< endl;

if(!pthread_create(&id, NULL, thread, NULL))

{

cout<<"Create thread success!"<< endl;

}

else

{

cout<<"Create thread failed!"<< endl;

}

pthread_join(id, NULL);

pthread_mutex_destroy(&mutex);

return 0;

}

编译: g++-o thread testthread.cpp-lpthread

说明:pthread库不是Linux系统默认的库,连接时需要使用静态库libpthread.a,所以在使用pthread_create()创建线程,以及调用pthread_atfork()函数建立fork处理程序时,需要链接该库。在编译中要加-lpthread参数。

2)条件变量(cond)

利用线程间共享的全局变量进行同步的一种机制。条件变量上的基本操作有:触发条件(当条件变为 true时);等待条件,挂起线程直到其他线程触发条件。

int pthread_cond_init(pthread_cond_t*cond,pthread_condattr_t*cond_attr);

int pthread_cond_wait(pthread_cond_t*cond,pthread_mutex_t*mutex);

int pthread_cond_timewait(pthread_cond_t*cond,pthread_mutex*mutex,const timespec*abstime);

int pthread_cond_destroy(pthread_cond_t*cond);

int pthread_cond_signal(pthread_cond_t*cond);

int pthread_cond_broadcast(pthread_cond_t*cond);//解除所有线程的阻塞

(1)初始化.init()或者pthread_cond_t cond=PTHREAD_COND_INITIALIER(前者为动态初始化,后者为静态初始化);属性置为NULL

(2)等待条件成立.pthread_wait,pthread_timewait.wait()释放锁,并阻塞等待条件变量为真,timewait()设置等待时间,仍未signal,返回ETIMEOUT(加锁保证只有一个线程wait)

(3)激活条件变量:pthread_cond_signal,pthread_cond_broadcast(激活所有等待线程)

(4)清除条件变量:destroy;无线程等待,否则返回EBUSY

对于

int pthread_cond_wait(pthread_cond_t*cond, pthread_mutex_t*mutex);

int pthread_cond_timedwait(pthread_cond_t*cond, pthread_mutex_t*mutex, const struct timespec*abstime);

一定要在mutex的锁定区域内使用。

如果要正确的使用pthread_mutex_lock与pthread_mutex_unlock,请参考

pthread_cleanup_push和pthread_cleanup_pop宏,它能够在线程被cancel的时候正确的释放mutex!

另外,posix1标准说,pthread_cond_signal与pthread_cond_broadcast无需考虑调用线程是否是mutex的拥有者,也就是说,可以在lock与unlock以外的区域调用。如果我们对调用行为不关心,那么请在lock区域之外调用吧。

说明:

(1)pthread_cond_wait自动解锁互斥量(如同执行了pthread_unlock_mutex),并等待条件变量触发。这时线程挂起,不占用CPU时间,直到条件变量被触发(变量为ture)。在调用 pthread_cond_wait之前,应用程序必须加锁互斥量。pthread_cond_wait函数返回前,自动重新对互斥量加锁(如同执行了pthread_lock_mutex)。

(2)互斥量的解锁和在条件变量上挂起都是自动进行的。因此,在条件变量被触发前,如果所有的线程都要对互斥量加锁,这种机制可保证在线程加锁互斥量和进入等待条件变量期间,条件变量不被触发。条件变量要和互斥量相联结,以避免出现条件竞争——个线程预备等待一个条件变量,当它在真正进入等待之前,另一个线程恰好触发了该条件(条件满足信号有可能在测试条件和调用pthread_cond_wait函数(block)之间被发出,从而造成无限制的等待)。

(3)pthread_cond_timedwait和 pthread_cond_wait一样,自动解锁互斥量及等待条件变量,但它还限定了等待时间。如果在abstime指定的时间内cond未触发,互斥量mutex被重新加锁,且pthread_cond_timedwait返回错误 ETIMEDOUT。abstime参数指定一个绝对时间,时间原点与 time和 gettimeofday相同:abstime= 0表示 1970年1月1日00:00:00 GMT。

(4)pthread_cond_destroy销毁一个条件变量,释放它拥有的资源。进入 pthread_cond_destroy之前,必须没有在该条件变量上等待的线程。

(5)条件变量函数不是异步信号安全的,不应当在信号处理程序中进行调用。特别要注意,如果在信号处理程序中调用 pthread_cond_signal或pthread_cond_boardcast函数,可能导致调用线程死锁。

示例程序1

#include<stdio.h>

#include<pthread.h>

#include"stdlib.h"

#include"unistd.h"

pthread_mutex_t mutex;

pthread_cond_t cond;

void hander(void*arg)

{

free(arg);

(void)pthread_mutex_unlock(&mutex);

}

void*thread1(void*arg)

{

pthread_cleanup_push(hander,&mutex);

while(1)

{

printf("thread1 is running\n");

pthread_mutex_lock(&mutex);

pthread_cond_wait(&cond,&mutex);

printf("thread1 applied the condition\n");

pthread_mutex_unlock(&mutex);

sleep(4);

}

pthread_cleanup_pop(0);

}

void*thread2(void*arg)

{

while(1)

{

printf("thread2 is running\n");

pthread_mutex_lock(&mutex);

pthread_cond_wait(&cond,&mutex);

printf("thread2 applied the condition\n");

pthread_mutex_unlock(&mutex);

sleep(1);

}

}

int main()

{

pthread_t thid1,thid2;

printf("condition variable study!\n");

pthread_mutex_init(&mutex,NULL);

pthread_cond_init(&cond,NULL);

pthread_create(&thid1,NULL,thread1,NULL);

pthread_create(&thid2,NULL,thread2,NULL);

sleep(1);

do

{

pthread_cond_signal(&cond);

}while(1);

sleep(20);

pthread_exit(0);

return 0;

}

示例程序2:

#include<pthread.h>

#include<unistd.h>

#include"stdio.h"

#include"stdlib.h"

static pthread_mutex_t mtx= PTHREAD_MUTEX_INITIALIZER;

static pthread_cond_t cond= PTHREAD_COND_INITIALIZER;

struct node

{

int n_number;

struct node*n_next;

}*head= NULL;

/*[thread_func]*/

static void cleanup_handler(void*arg)

{

printf("Cleanup handler of second thread./n");

free(arg);

(void)pthread_mutex_unlock(&mtx);

}

static void*thread_func(void*arg)

{

struct node*p= NULL;

pthread_cleanup_push(cleanup_handler, p);

while(1)

{

//这个mutex主要是用来保证pthread_cond_wait的并发性

pthread_mutex_lock(&mtx);

while(head== NULL)

{

//这个while要特别说明一下,单个pthread_cond_wait功能很完善,为何

//这里要有一个while(head== NULL)呢?因为pthread_cond_wait里的线

//程可能会被意外唤醒,如果这个时候head!= NULL,则不是我们想要的情况。

//这个时候,应该让线程继续进入pthread_cond_wait

// pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,

//然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立

//而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);,再读取资源

//用这个流程是比较清楚的/*block-->unlock-->wait() return-->lock*/

pthread_cond_wait(&cond,&mtx);

p= head;

head= head->n_next;

printf("Got%d from front of queue/n", p->n_number);

free(p);

}

pthread_mutex_unlock(&mtx);//临界区数据操作完毕,释放互斥锁

}

pthread_cleanup_pop(0);

return 0;

}

int main(void)

{

pthread_t tid;

int i;

struct node*p;

//子线程会一直等待资源,类似生产者和消费者,但是这里的消费者可以是多个消费者,而

//不仅仅支持普通的单个消费者,这个模型虽然简单,但是很强大

pthread_create(&tid, NULL, thread_func, NULL);

sleep(1);

for(i= 0; i< 10; i++)

{

p=(struct node*)malloc(sizeof(struct node));

p->n_number= i;

pthread_mutex_lock(&mtx);//需要操作head这个临界资源,先加锁,

p->n_next= head;

head= p;

pthread_cond_signal(&cond);

pthread_mutex_unlock(&mtx);//解锁

sleep(1);

}

printf("thread 1 wanna end the line.So cancel thread 2./n");

//关于pthread_cancel,有一点额外的说明,它是从外部终止子线程,子线程会在最近的取消点,退出

//线程,而在我们的代码里,最近的取消点肯定就是pthread_cond_wait()了。

pthread_cancel(tid);

pthread_join(tid, NULL);

printf("All done-- exiting/n");

return 0;

}

3)信号量

如同进程一样,线程也可以通过信号量来实现通信,虽然是轻量级的。

信号量函数的名字都以"sem_"打头。线程使用的基本信号量函数有四个。

#include<semaphore.h>

int sem_init(sem_t*sem, int pshared, unsigned int value);

这是对由sem指定的信号量进行初始化,设置好它的共享选项(linux只支持为0,即表示它是当前进程的局部信号量),然后给它一个初始值VALUE。

两个原子操作函数:

int sem_wait(sem_t*sem);

int sem_post(sem_t*sem);

这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。

sem_post:给信号量的值加1;

sem_wait:给信号量减1;对一个值为0的信号量调用sem_wait,这个函数将会等待直到有其它线程使它不再是0为止。

int sem_destroy(sem_t*sem);

这个函数的作用是再我们用完信号量后都它进行清理。归还自己占有的一切资源。

示例代码:

#include<stdlib.h>

#include<stdio.h>

#include<unistd.h>

#include<pthread.h>

#include<semaphore.h>

#include<errno.h>

#define return_if_fail(p) if((p)== 0){printf("[%s]:func error!/n", __func__);return;}

typedef struct _PrivInfo

{

sem_t s1;

sem_t s2;

time_t end_time;

}PrivInfo;

static void info_init(PrivInfo* thiz);

static void info_destroy(PrivInfo* thiz);

static void* pthread_func_1(PrivInfo* thiz);

static void* pthread_func_2(PrivInfo* thiz);

int main(int argc, char** argv)

{

pthread_t pt_1= 0;

pthread_t pt_2= 0;

int ret= 0;

PrivInfo* thiz= NULL;

thiz=(PrivInfo*)malloc(sizeof(PrivInfo));

if(thiz== NULL)

{

printf("[%s]: Failed to malloc priv./n");

return-1;

}

info_init(thiz);

ret= pthread_create(&pt_1, NULL,(void*)pthread_func_1, thiz);

if(ret!= 0)

{

perror("pthread_1_create:");

}

ret= pthread_create(&pt_2, NULL,(void*)pthread_func_2, thiz);

if(ret!= 0)

{

perror("pthread_2_create:");

}

pthread_join(pt_1, NULL);

pthread_join(pt_2, NULL);

info_destroy(thiz);

return 0;

}

static void info_init(PrivInfo* thiz)

{

return_if_fail(thiz!= NULL);

thiz->end_time= time(NULL)+ 10;

sem_init(&thiz->s1, 0, 1);

sem_init(&thiz->s2, 0, 0);

return;

}

static void info_destroy(PrivInfo* thiz)

{

return_if_fail(thiz!= NULL);

sem_destroy(&thiz->s1);

sem_destroy(&thiz->s2);

free(thiz);

thiz= NULL;

return;

}

static void* pthread_func_1(PrivInfo* thiz)

{

return_if_fail(thiz!= NULL);

while(time(NULL)< thiz->end_time)

{

sem_wait(&thiz->s2);

printf("pthread1: pthread1 get the lock./n");

sem_post(&thiz->s1);

printf("pthread1: pthread1 unlock/n");

sleep(1);

}

return;

}

static void* pthread_func_2(PrivInfo* thiz)

{

return_if_fail(thiz!= NULL);

while(time(NULL)< thiz->end_time)

{

sem_wait(&thiz->s1);

printf("pthread2: pthread2 get the unlock./n");

sem_post(&thiz->s2);

printf("pthread2: pthread2 unlock./n");

sleep(1);

}

return;

}

通过执行结果后,可以看出,会先执行线程二的函数,然后再执行线程一的函数。它们两就实现了同步

阅读剩余
THE END