进程的PV操作

1. 信号量基本术语

 

      现代计算机系统中,多个进程可以并发执行,进程间必然存在共享资源和相互合作的问题。

      同步主要是用户多个进程相互协作,共同完成任务,是进程间的直接制约问题;互斥则主要是为了多个进程分时使用有限的资源。

 

       信号量(semaphore)是1965年由荷兰人Dijkstra提出的一种卓有成效的进程间同步及互斥工具。信号量在操作系统中实现时一般作为一个整数变量,这种信号量称为整型信号量。信号量S的物理意义:

 

      S >= 0表示某资源的可用数;

      S<0 其绝对值表示阻塞队列中等待该资源的进程数目;

 

信号量的两个操作方法是PV,P操作为S=S-1;表示申请一个资源,V操作为S=S+1;表示释放一个资源。因为对整数的加减1操作是在一个指令完成的,而硬件能够保证中断只能发生在指令之间,所以PV操作不会被中断打扰执行结果。

       P

      {

             S = S-1;

             if(s<0)

                 Wait(S);  --------当前进程进入等待队列等待

       }

 

       V

       {

             S=S+1;

             if(S<=0)

                 Resume(S); ----------唤醒等待队列中的一个进程

        }

2.利用信号量实现互斥

     初始化信号量mutex = 1; 当进程进入临界区时执行P操作,退出临界区时执行V操作。

       P(mutex)

         临界区代码;(操作互斥资源)

      V(mutex)

 

3. 利用信号量实现同步

  此时可以把信号想象成代表一个消息。当S=0表示表示消息未产生;当S>0则表示消息已经产生。例如:

    (1)单缓冲区的生产者和消费者问题。

  生产者进程P1不断地生产产品送入缓冲区,消费者进程P2不断地从缓冲区中提取产品消费。为了实现P1与P2进程间的同步,需要设置一个信号量S1,并且初始化为1,表示缓冲区为空,可以将产品放入缓冲区中;还需要设置另一个另一个信号量S2,初始值为0,表示缓冲区没有产品,可以提取消费。

 

P1:生产一个产品--->P(S1)测试缓冲区是否为空----->产品送缓冲区---->V(S2)设置有产品---->重复

 

P2: P(S2)测试是否有产品----->从缓冲区取出产品------->V(S1)设置缓冲区为空------->消费--->重复

 

     (2)多缓冲区同步问题

      设有一个生产者和一个消费者,缓冲区可以存放n件物品,生产者不断地生产产品,消费者不断地消费产品。

     设置3个信号量,S, S1,S2。其中S是一个互斥信号量初值为1,对缓冲区资源进行互斥控制,S1表示是否可以将物品放入缓冲区,初值为n,S2表示缓冲区中是否有物品,初值为0。同步过程如下:

 

P1:生产一个产品----->P(S1)--->P(S)--->产品送缓冲区--->V(S)---->V(S2)

P2:P(S2)------>P(S)--->从缓冲区取出一个产品----->V(S)----->V(S1)----->消费

 

 

附上在Windows和Unix平台使用信号量的源码:

  1. 至于什么是信号量(Semaphore),网上相关资料多得很,一搜一大把,我就不做重复劳动了。只是把关于使用信号量的示例程序贴一下当作笔记,万一能对大家有点点帮助那就更好了。Windows 平台的代码来源于 MSDN,Unix 平台的代码是 Google 来的。  
  2.   
  3. Part 1 - Windows 平台信号量(Semaphore)示例程序  
  4. #include <stdio.h>  
  5. #include <Windows.h>  
  6.   
  7. #define MAX_SEM_COUNT 10  
  8. #define THREADCOUNT 12  
  9.   
  10. HANDLE ghSemaphore;  
  11.   
  12. DWORD WINAPI ThreadProc( LPVOID );  
  13.   
  14. void main(int argc, char* argv[])  
  15. {  
  16.     HANDLE aThread[THREADCOUNT];  
  17.     DWORD ThreadID;  
  18.     int i;  
  19.   
  20.     // Create a semaphore with initial and max counts of MAX_SEM_COUNT  
  21.   
  22.     ghSemaphore = CreateSemaphore(   
  23.         NULL,           // default security attributes - lpSemaphoreAttributes是信号量的安全属性  
  24.         MAX_SEM_COUNT,  // initial count - lInitialCount是初始化的信号量  
  25.         MAX_SEM_COUNT,  // maximum count - lMaximumCount是允许信号量增加到最大值  
  26.         NULL);          // unnamed semaphore - lpName是信号量的名称  
  27.   
  28.     if (ghSemaphore == NULL)   
  29.     {  
  30.         printf("CreateSemaphore error: %d/n", GetLastError());  
  31.         return;  
  32.     }  
  33.   
  34.     // Create worker threads  
  35.   
  36.     for( i=0; i <THREADCOUNT; i++ )  
  37.     {  
  38.         aThread[i] = CreateThread(   
  39.             NULL,       // default security attributes  
  40.             0,          // default stack size  
  41.             (LPTHREAD_START_ROUTINE) ThreadProc,   
  42.             NULL,       // no thread function arguments  
  43.             0,          // default creation flags  
  44.             &ThreadID); // receive thread identifier  
  45.   
  46.         if( aThread[i] == NULL )  
  47.         {  
  48.             printf("CreateThread error: %d/n", GetLastError());  
  49.             return;  
  50.         }  
  51.     }  
  52.   
  53.     // Wait for all threads to terminate  
  54.   
  55.     WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);  
  56.   
  57.     // Close thread and semaphore handles  
  58.   
  59.     for( i=0; i <THREADCOUNT; i++ )  
  60.         CloseHandle(aThread[i]);  
  61.   
  62.     CloseHandle(ghSemaphore);  
  63. }  
  64.   
  65. DWORD WINAPI ThreadProc( LPVOID lpParam )  
  66. {  
  67.     DWORD dwWaitResult;  
  68.     BOOL bContinue=TRUE;  
  69.   
  70.     while(bContinue)  
  71.     {  
  72.         // Try to enter the semaphore gate.  
  73.         dwWaitResult = WaitForSingleObject(   
  74.             ghSemaphore,   // handle to semaphore  
  75.             0L);           // zero-second time-out interval  
  76.   
  77.         switch (dwWaitResult)   
  78.         {   
  79.             // The semaphore object was signaled.  
  80.         case WAIT_OBJECT_0:   
  81.             // TODO: Perform task  
  82.             printf("Thread %d: wait succeeded/n", GetCurrentThreadId());  
  83.               
  84.             // Ensure a thread performs only once  
  85.             bContinue=FALSE;  
  86.   
  87.             // Simulate thread spending time on task  
  88.             Sleep(5);  
  89.   
  90.             // Release the semaphore when task is finished  
  91.   
  92.             if (!ReleaseSemaphore(   
  93.                 ghSemaphore,  // handle to semaphore - hSemaphore是要增加的信号量句柄  
  94.                 1,            // increase count by one - lReleaseCount是增加的计数  
  95.                 NULL) )       // not interested in previous count - lpPreviousCount是增加前的数值返回  
  96.             {  
  97.                 printf("ReleaseSemaphore error: %d/n", GetLastError());  
  98.             }  
  99.             break;   
  100.   
  101.             // The semaphore was nonsignaled, so a time-out occurred.  
  102.         case WAIT_TIMEOUT:   
  103.             printf("Thread %d: wait timed out/n", GetCurrentThreadId());  
  104.             break;   
  105.         }  
  106.     }  
  107.     return TRUE;  
  108. }  
  109.   
  110.   
  111. Part 2 - Unix 平台信号量(Semaphore)示例程序  
  112. /* semabinit.c - initialize a semaphore for use by programs sema and semb */  
  113.   
  114. #include <sys/types.h>  
  115. #include <sys/ipc.h>  
  116. #include <sys/sem.h>  
  117. #include <stdio.h>  
  118.   
  119. /* The semaphore key is an arbitrary long integer which serves as an 
  120. external identifier by which the semaphore is known to any program 
  121. that wishes to use it. */  
  122.   
  123. #define KEY (1492)  
  124.   
  125. void main()  
  126. {  
  127. int id; /* Number by which the semaphore is known within a program */  
  128.   
  129. /* The next thing is an argument to the semctl() function. Semctl() 
  130. does various things to the semaphore depending on which arguments 
  131. are passed. We will use it to make sure that the value of the 
  132. semaphore is initially 0. */  
  133.   
  134. union semun {  
  135. int val;  
  136. struct semid_ds *buf;  
  137. ushort * array;  
  138. } argument;  
  139.   
  140. argument.val = 0;  
  141.   
  142. /* Create the semaphore with external key KEY if it doesn't already 
  143. exists. Give permissions to the world. */  
  144.   
  145. id = semget(KEY, 1, 0666 | IPC_CREAT);  
  146.   
  147. /* Always check system returns. */  
  148.   
  149. if(id <0)  
  150. {  
  151. fprintf(stderr, "Unable to obtain semaphore. ");  
  152. exit(0);  
  153. }  
  154.   
  155. /* What we actually get is an array of semaphores. The second 
  156. argument to semget() was the array dimension - in our case 
  157. 1. */  
  158.   
  159. /* Set the value of the number 0 semaphore in semaphore array 
  160. # id to the value 0. */  
  161.   
  162. if( semctl(id, 0, SETVAL, argument) <0)  
  163. {  
  164. fprintf( stderr, "Cannot set semaphore value. ");  
  165. }  
  166. else  
  167. {  
  168. fprintf(stderr, "Semaphore %d initialized. ", KEY);  
  169. }  
  170. }  
  171.   
  172.   
  173. /* Semaphore example program a (sema.c) */  
  174. /* We have two programs, sema and semb. Semb may be initiated at any 
  175. time, but will be forced to wait until sema is executed. Sema and 
  176. semb do not have to be executed by the same user! */  
  177.   
  178. #include <stdio.h>  
  179. #include <sys/types.h>  
  180. #include <sys/ipc.h>  
  181. #include <sys/sem.h>  
  182.   
  183. #define KEY (1492)  
  184. /* This is the external name by which the semaphore is known to any 
  185. program that wishes to Access it. */  
  186.   
  187. void main()  
  188. {  
  189. int id; /* Internal identifier of the semaphore. */  
  190. struct sembuf operations[1];  
  191. /* An "array" of one operation to perform on the semaphore. */  
  192.   
  193. int retval; /* Return value from semop() */  
  194.   
  195. /* Get the index for the semaphore with external name KEY. */  
  196. id = semget(KEY, 1, 0666);  
  197. if(id <0)  
  198. /* Semaphore does not exist. */  
  199. {  
  200. fprintf(stderr, "Program sema cannot find semaphore, exiting. ");  
  201. exit(0);  
  202. }  
  203.   
  204. /* Do a semaphore V-operation. */  
  205. printf("Program sema about to do a V-operation. ");  
  206.   
  207. /* Set up the sembuf structure. */  
  208. /* Which semaphore in the semaphore array : */  
  209. operations[0].sem_num = 0;  
  210. /* Which operation? Add 1 to semaphore value : */  
  211. operations[0].sem_op = 1;  
  212. /* Set the flag so we will wait : */  
  213. operations[0].sem_flg = 0;  
  214.   
  215. /* So do the operation! */  
  216. retval = semop(id, operations, 1);  
  217.   
  218. if(retval == 0)  
  219. {  
  220. printf("Successful V-operation by program sema. ");  
  221. }  
  222. else  
  223. {  
  224. printf("sema: V-operation did not succeed. ");  
  225. perror("REASON");  
  226. }  
  227. }  
  228.   
  229. /* Think carefully about what the V-operation does. If sema is executed 
  230. twice, then semb can execute twice. */  
  231.   
  232.   
  233. /* Semaphore example program b (semb.c) */  
  234. /* We have two programs, sema and semb. Semb may be initiated at any 
  235. time, but will be forced to wait until sema is executed. Sema and 
  236. semb do not have to be executed by the same user! */  
  237.   
  238. /* HOW TO TEST: 
  239. Execute semb & 
  240. The & is important - otherwise you would have have to move to 
  241. a different terminal to execute sema. 
  242.  
  243. Then execute sema. 
  244. */  
  245.   
  246. #include <stdio.h>  
  247. #include <sys/types.h>  
  248. #include <sys/ipc.h>  
  249. #include <sys/sem.h>  
  250.   
  251. #define KEY (1492)  
  252. /* This is the external name by which the semaphore is known to any 
  253. program that wishes to access it. */  
  254.   
  255. void main()  
  256. {  
  257. int id; /* Internal identifier of the semaphore. */  
  258. struct sembuf operations[1];  
  259. /* An "array" of one operation to perform on the semaphore. */  
  260.   
  261. int retval; /* Return value from semop() */  
  262.   
  263. /* Get the index for the semaphore with external name KEY. */  
  264. id = semget(KEY, 1, 0666);  
  265. if(id <0)  
  266. /* Semaphore does not exist. */  
  267. {  
  268. fprintf(stderr, "Program semb cannot find semaphore, exiting. ");  
  269. exit(0);  
  270. }  
  271.   
  272. /* Do a semaphore P-operation. */  
  273. printf("Program semb about to do a P-operation. ");  
  274. printf("Process id is %d ", getpid());  
  275.   
  276. /* Set up the sembuf structure. */  
  277. /* Which semaphore in the semaphore array : */  
  278. operations[0].sem_num = 0;  
  279. /* Which operation? Subtract 1 from semaphore value : */  
  280. operations[0].sem_op = -1;  
  281. /* Set the flag so we will wait : */  
  282. operations[0].sem_flg = 0;  
  283.   
  284. /* So do the operation! */  
  285. retval = semop(id, operations, 1);  
  286.   
  287. if(retval == 0)  
  288. {  
  289. printf("Successful P-operation by program semb. ");  
  290. printf("Process id is %d ", getpid());  
  291. }  
  292. else  
  293. {  
  294. printf("semb: P-operation did not succeed. ");  
  295. }  
  296. }  
  297.   
  298. /* Think carefully about what the V-operation does. If sema is executed 
  299. twice, then semb can execute twice. */ 
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值