GVKun编程网logo

IPC研究(4) ---- semaphores(IPC研究所)

14

最近很多小伙伴都在问IPC研究和4----semaphores这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展c#–SkipSemaphoreSlim而不是等待、c#–具有动态ma

最近很多小伙伴都在问IPC研究4 ---- semaphores这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展c# – Skip SemaphoreSlim而不是等待、c# – 具有动态maxCount的SemaphoreSlim、c#并发semaphoreslim、C/C++ 信号量 CreateSemaphore 用法等相关知识,下面开始了哦!

本文目录一览:

IPC研究(4) ---- semaphores(IPC研究所)

IPC研究(4) ---- semaphores(IPC研究所)

============================================================
IPC --- System V IPC --- semaphores

Related System Calls:
[designed to work for arrays of semaphore values]
#include <sys/sem.h>
semctl
semget
semop


Basics:
Purpose: provide the feature for a single process to have exclusive access to a resource
Application scenes: multi-threaded programs, multiprocess programs or a combine of the two
General definition: two operations -- P(wait) and V(signal)

=> binaray semaphore (0,1)
=> general semaphore (0,1,2,...)

和file类似,不同的进程会有不同的semaphore identifier,但是,它们都指向同一个semaphore。(就像fd和inode)
对于file,不同的进程用filename来得到file descriptors,对于semaphore,不同的进程用key来得到不同的semaphore identifiers。

用semaphore通信的各个进程间,需要有个共同的key。


Analysis:
1. Linux Kernel是如何支持semaphore通信机制的呢?
struct_task结构中有相应的semaphore的域,如果systemV IPC支持被编译进来,就可以支持。

2. semaphore主要是用来解决资源访问冲突的问题的。对于资源访问的竞争问题,有如下模型:
process1 |
process2 | <==> RESOURCE
process3 |
要使访问资源不因为出现竞争状态而出现不想要的结果,有两种方法。
第一,在resource侧做控制,组织多个进程同时访问,或者对将访问block。比如file lock
第二,在访问的process间做控制,使得他们能够互相通信,从而解决访问冲突。
在Linux中,第二种解决方案,就是semaphore。



Examples:


#ifndef _JAMES_C_SEMAPHORE_H
#define _JAMES_C_SEMAPHORE_H

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

union semun
{
	int val;		/* value for SETVAL */
	struct semid_ds *buf;	/* buffer for IPC_STAT, IPC_SET */
	unsigned short *array;	/* array for GETALL SETALL */
	struct seminfo __buf;	/* buffer for IPC_INFO (Linux-specific) */
};

int set_semvalue(int sem_id);
void del_semvalue(int sem_id);
int semaphore_p(int sem_id);
int semaphore_v(int sem_id);

#endif 

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "mysem.h"

int set_semvalue(int sem_id)
{
	union semun sem_union;
	sem_union.val = 1;
	if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
		return -1;
	return 0;
}

void del_semvalue(int sem_id)
{
	union semun sem_union;
	if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
		perror("Failed to delete semaphore");
}

int semaphore_p(int sem_id)
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = -1;	/* *P() */
	sem_b.sem_flg = SEM_UNDO;
	if (semop(sem_id, &sem_b, 1) == -1)
	{
		fprintf(stderr, "semaphore_p failed\n");
		return -1;
	}
	return 0;
}

int semaphore_v(int sem_id)
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
	sem_b.sem_op = 1;
	sem_b.sem_flg = SEM_UNDO;
	if (semop(sem_id, &sem_b, 1) == -1)
	{
		fprintf(stderr, "semaphore_v failed\n");
		return -1;
	}
	return 0;
}

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "mysem.h"

int main(int argc, char *argv[])
{
	int sem_id;
	int i;
	int pause_time;
	char op_char;

	srand( (unsigned int)getpid() );
	op_char = ''a'' + rand()%26; /* other process */

	sem_id = semget( (key_t)1234, 1, 0666 | IPC_CREAT);

	if (argc > 1)
	{
		if ( set_semvalue(sem_id) < 0)
		{
			fprintf(stderr, "Failed to initialize semaphore\n");
			exit(-1);
		}
		op_char = ''X'';	/* creation process */
		sleep(2);
	}
	for (i=0; i<5; i++)
	{
		if (semaphore_p(sem_id) < 0)
			exit(-1);
		printf("%c", op_char); fflush(stdout);
		pause_time = rand()%3;
		sleep(pause_time);
		printf("%c", op_char); fflush(stdout);
		if (semaphore_v(sem_id) < 0)
			exit(-1);
		sleep(pause_time);
	}
	printf("\n%d - finished\n", getpid());

	if (argc > 1)
	{
		sleep(10);
		del_semvalue(sem_id);
	}
	return 0;
}


c# – Skip SemaphoreSlim而不是等待

c# – Skip SemaphoreSlim而不是等待

我在Async / Await函数中有一部分代码,我只希望一次执行一个线程.

通过创建新的SemaphoreSlim(1)并使用WaitAsync / Release,这相对简单.结果是第一个线程执行而其他线程等待然后逐个执行.

我想要实现的目标实际上略有不同.我希望其他线程不要等待,但要退出该函数(即我不想阻止其他线程).因此,如果有一个属性“NumberOfThreadsCurrentlyExecuting”,我将有效地拥有一个If Semaphore.NumberOfThreadsCurrentlyExecuting> 0然后返回.

但这样的财产不存在.有没有人知道解决这个问题的方法?

谢谢
查尔斯

解决方法

您可以使用Monitor,而不是Semaphore.

如果您调用TryEnter并且它失败,则另一个线程处于“锁定”状态.

这是线程安全的(与检查信号量计数不同),相当简单:

//使用somethign如:object sync = new object();

bool lockTaken = Monitor.TryEnter(sync);
try
{
  if (lockTaken) 
  {
      // You're here - do your work
  }
  else
  {
      // Something else was in the thread - exit?
      return;
  }
}
finally
{
   if (lockTaken) Monitor.Exit(sync);
}

c# – 具有动态maxCount的SemaphoreSlim

c# – 具有动态maxCount的SemaphoreSlim

我遇到了一个问题,我需要限制对另一个Web服务器的调用次数.它会有所不同,因为服务器是共享的,也许它可能有更多或更少的容量.

我在考虑使用SemaphoreSlim类,但是没有公共属性来更改最大计数.

我应该将我的SemaphoreSlim类包装在另一个将处理最大计数的类中吗?有没有更好的方法?

编辑:

这是我正在尝试的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Semaphore
{
class Program
{
    static SemaphoreSlim _sem = new SemaphoreSlim(10,10000);

    static void Main(string[] args)
    {
        int max = 15;

        for (int i = 1; i <= 50; i++)
        {
            new Thread(Enter).Start(new int[] { i,max});
        }

        Console.ReadLine();

        max = 11;

        for (int i = 1; i <= 50; i++)
        {
            new Thread(Enter).Start(new int[] { i,max });
        }
    }

    static void Enter(object param)
    {
        int[] arr = (int[])param;
        int id = arr[0];
        int max = arr[1];

        try
        {
            Console.WriteLine(_sem.CurrentCount);

            if (_sem.CurrentCount <= max)
                _sem.Release(1);
            else
            {
                _sem.Wait(1000);

                Console.WriteLine(id + " wants to enter");

                Thread.Sleep((1000 * id) / 2); // can be here at

                Console.WriteLine(id + " is in!"); // Only three threads

            }
        }
        catch(Exception ex)
        {
            Console.WriteLine("opps ",id);
            Console.WriteLine(ex.Message);
        }
        finally            
        {
            _sem.Release();
        }
    }
}
}

问题:

1-_sem.Wait(1000)应该取消执行超过1000ms的线程,不是吗?

2 – 我是否有使用发布/等待的想法?

解决方法

您无法更改最大计数,但您可以创建具有非常高的最大计数的SemaphoreSlim,并保留其中一些.见 this constructor.

所以我们假设绝对最大并发调用数是100,但最初你希望它是25.你初始化你的信号量:

SemaphoreSlim sem = new SemaphoreSlim(25,100);

因此25是可以同时服务的请求数.你保留了其他75.

如果您想增加允许的数量,只需调用Release(num).如果您调用了Release(10),那么该数字将变为35.

现在,如果要减少可用请求的数量,则必须多次调用WaitOne.例如,如果要从可用计数中删除10:

for (var i = 0; i < 10; ++i)
{
    sem.WaitOne();
}

这有可能阻塞,直到其他客户端释放信号量.也就是说,如果您允许35个并发请求,并且您希望将其减少到25,但是已经有35个客户端具有活动请求,那么WaitOne将阻塞,直到客户端调用Release,并且循环将不会终止,直到10个客户端发布.

c#并发semaphoreslim

c#并发semaphoreslim

该类限制了用时访问同一资源的线程数量,下面写一段代码来讲解他的用法

class Program
{
static SemaphoreSlim _semaphore = new SemaphoreSlim(4);
static void acquireSemaphore(string name, int seconds)
{
Console.WriteLine("{0} wait",name);
_semaphore.Wait();
Console.WriteLine("{0} access",name);
Thread.Sleep(TimeSpan.FromSeconds(seconds));
Console.WriteLine("{0} Release", name);
_semaphore.Release();
}
static void Main(string[] args)
{
for(int i = 1; i <= 6; i++)
{
string threadName = "thread" + i;
int secondsToWait = 2 + 2 * i;
var t = new Thread(() => acquireSemaphore(threadName, secondsToWait));
t.Start();
}
Console.ReadKey();
这里我写了一个函数来获取SemaphoreSlim 信号量,在创建时static SemaphoreSlim _semaphore = new SemaphoreSlim(4);设置可以同时访问的线程数为4,也就是说运行后的情况应该是在线程1、2、3、4访问该信号量没有释放之前,线程5会一直处于等待状态,下面我们运行一下看看结果。

从运行结果我们可以看到,线程5,6处于等待状态,直到1释放5获得信号量,2释放6获得信号量。
---------------------
作者:Maybe_ch
来源:CSDN
原文:https://blog.csdn.net/Maybe_ch/article/details/84818373
版权声明:本文为博主原创文章,转载请附上博文链接!

C/C++ 信号量 CreateSemaphore 用法

C/C++ 信号量 CreateSemaphore 用法

HANDLE CreateSemaphore(
  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,  // SD
  LONG lInitialCount,                          // initial count
  LONG lMaximumCount,                          // maximum count
  LPCTSTR lpName                           // object name
)
此函数可用来创建或打开一个信号量先看参数说明
lpSemaphoreAttributes:为信号量的属性,一般可以设置为NULL
lInitialCount:信号量初始值,必须大于等于0,而且小于等于 lpMaximumCount,如果lInitialCount 的初始值为0,则该信号量默认为unsignal状态,如果lInitialCount的初始值大于0,则该信号量默认为signal状态,
lMaximumCount: 此值为设置信号量的最大值,必须大于0
lpName:信号量的名字,长度不能超出MAX_PATH ,可设置为NULL,表示无名的信号量。当lpName不为空时,可创建有名的信号量,若当前信号量名与已存在的信号量的名字相同时,则该函数表示打开该信号量,这时参数lInitialCount 和
lMaximumCount 将被忽略。
函数调用成功返回信号量句柄。
释放信号量函数:
BOOL ReleaseSemaphore( HANDLE hSemaphore, // handle to semaphore
LONG lReleaseCount, // count increment amount
LPLONG lpPreviousCount // previous count);
参数说明:

hSemaphore:信号量句柄,
lReleaseCount:释放的数量,一般完成一个等待后调用此函数释放一个信号量,使得信号量平衡。
lpPreviousCount :存放以前信号量的数量 ,一般可为NULL.

打开信号量函数:
HANDLE OpenSemaphore( DWORD dwDesiredAccess, // access BOOL bInheritHandle, // inheritance option LPCTSTR lpName// object name );
此函数打开一个有名的信号量
参数说明:
dwDesiredAccess:对信号量的访问权限,取值可以是SEMAPHORE_ALL_ACCESS,可对信号量执行尽可能多的操作;可以是SEMAPHORE_MODIFY_STATE,允许使用ReleaseSemaphore释放信号量,达到修改信号量;还可以是SYNCHRONIZE,用等待函数异步的等待信号量变为signal状态
bInheritHandle:如果为true,信号量句柄可被继承,反之不可继承。
lpName :信号量的名字。

别忘了最后使用完成后用CloseHandle()关闭信号量句柄
暂时API写到此为止,以后还有关信号量的函数,再继续添加。下面通过一个例子,来说明使用信号量来世线程同步的例子,要求创建三个线程,每个线程次打印十次ID,必须三个线程一次打印。注意:在使用WaitForSingleObject等待信号量句柄时,若信号量为signal状态,则wait过后信号量自动减1,直到使用ReleaseSemaphore释放信号量,信号量才可增加
代码如下:
说明:创建控制台程序。

#include "stdafx.h"
#include <Windows.h>


DWORD WINAPI Thread_1(LPVOID param);
DWORD WINAPI Thread_2(LPVOID param);
DWORD WINAPI Thread_3(LPVOID param);

HANDLE hSM_1;
HANDLE hSM_2;
HANDLE hSM_3;

HANDLE hThread_1;
HANDLE hThread_2;
HANDLE hThread_3;

int _tmain(int argc, _TCHAR* argv[])
{

//创建三个信号量

hSM_1 = CreateSemaphore(NULL, 1, 1, L"A");//开始为signal状态
hSM_2 = CreateSemaphore(NULL, 0, 1, L"B");//开始为unsignal状态,等待hSM_1释放
hSM_3 = CreateSemaphore(NULL, 0, 1, L"C");//开始为unsignal状态,等待hSM_2

//创建三个线程

hThread_1 = CreateThread(NULL, 0, Thread_1, NULL, 0, NULL);
hThread_2 = CreateThread(NULL, 0, Thread_2, NULL, 0, NULL);
hThread_3 = CreateThread(NULL, 0, Thread_3, NULL, 0, NULL);
//等待三个线程都执行完
WaitForSingleObject(hThread_1, INFINITE);
WaitForSingleObject(hThread_2, INFINITE);
WaitForSingleObject(hThread_3, INFINITE);

//三个线程都执行完
printf("\n\n\t main end \n");
//关闭句柄
CloseHandle(hThread_1);
CloseHandle(hThread_2);
CloseHandle(hThread_3);
CloseHandle(hSM_1);
CloseHandle(hSM_2);
CloseHandle(hSM_3);
return 0;
}

DWORD WINAPI Thread_1(LPVOID param)
{
for (int i = 0; i < 10; i ++)
{
DWORD dwWait = WaitForSingleObject(hSM_1, INFINITE);

//每一个wait过后信号量的数量自动减1,这样就达到了控制同步

printf("A");
ReleaseSemaphore(hSM_2, 1, NULL);
}
return 0;
}

DWORD WINAPI Thread_2(LPVOID param)
{
for (int i = 0; i < 10; i ++)
{
WaitForSingleObject(hSM_2, INFINITE);
printf("B");
ReleaseSemaphore(hSM_3, 1, NULL);
}
return 0;
}

DWORD WINAPI Thread_3(LPVOID param)
{
for (int i = 0; i < 10; i ++)
{
WaitForSingleObject(hSM_3, INFINITE);
printf("C ");
ReleaseSemaphore(hSM_1, 1, NULL);
}
return 0;
}

 

 

运行结果:
C/C++ 信号量 CreateSemaphore 用法 - 快乐男孩 - 快乐男孩的博客

 

我们今天的关于IPC研究4 ---- semaphores的分享已经告一段落,感谢您的关注,如果您想了解更多关于c# – Skip SemaphoreSlim而不是等待、c# – 具有动态maxCount的SemaphoreSlim、c#并发semaphoreslim、C/C++ 信号量 CreateSemaphore 用法的相关信息,请在本站查询。

本文标签: